Guys I am doing polynomial evaluation and using algorithms such as Naive, Horner and FFT
now there is one statement in my question that states.
Run a variation of the naïve algorithm, where the exponentiation
is performed by repeated squaring, a decrease-by-half algorithm
I do not understand it, My current Naive algorithm is:
public Complex naive(Polynomial poly, Complex x) {
Complex p = new Complex();
for (int i = poly.getCoef().length - 1; i >= 0; i--) {
Complex power = new Complex(1, 0);
for (int j = 1; j <= i; j++) {
power = power.multiply(x);
}
p = p.add(poly.getCoef()[i].multiply(power));
multiplyCountNaive++;
}
return p;
}
Kindly explain what needs to be modified.
Thank you
I got it it was supposed to be like this
public Complex naive2(Polynomial poly, Complex x) {
Complex p = new Complex();
for (int i = poly.getCoef().length - 1; i >= 0; i--) {
p = p.add(poly.getCoef()[i].multiply(expo(x, i)));
multiplyCountNaive2++;
}
return p;
}
private Complex expo(Complex a, int b) {
if (b == 0) {
return new Complex(1, 0);
} else if (b == 1) {
return a;
}
if (b % 2 == 0) {
return expo(a.multiply(a), b / 2);
} else {
return a.multiply(expo(a.multiply(a), (b - 1) / 2));
}
}
Related
How I find among all pairs a and b with a "least common multiple" LCM(a,b) = 498960 and a "greatest common divisor" GDM(a, b) = 12 a pair with minimum sum a + b?
I solved this with O(n^2) time:
public class FindLcmAndGcdClass {
private int findGcd(int a, int b) {
if (a % b == 0) {
return b;
}
return findGcd(b, a % b);
}
private int findLcm(int a, int b, int gcd) {
return (a * b) / gcd;
}
private void run() {
int minSum = Integer.MAX_VALUE;
int foundNumberOne = 0;
int foundNumberTwo = 0;
for (int i = 12; i <= 498960; i += 12) {
for (int j = i; j <= 498960; j += 12) {
int gcd;
if (i < j) {
gcd = findGcd(j, i);
} else {
gcd = findGcd(i, j);
}
int lcm = findLcm(i, j, gcd);
if (gcd == 12 && lcm == 498960 && i + j < minSum) {
minSum = i + j;
foundNumberOne = i;
foundNumberTwo = j;
}
}
}
System.out.println(minSum);
System.out.println(foundNumberOne);
System.out.println(foundNumberTwo);
}
public static void main(String[] args) {
var o = new FindLcmAndGcdClass();
o.run();
}
}
And it executes quite slowly! I guess the problem can be solved with Dynamic Programming. Can anyone help with more fast solution?
I am not sure if this question can be solved with dynamic programming, but I think of a solution with time complexity O(sqrt(LCM * GCD)).
It is well known that for any two integers a and b, LCM(a, b) * GCD(a, b) = a * b. Therefore, you can first calculate the product of the gcd and lcm, (which is 5987520 in this question). Then for all its factors under sqrt(LCM * GCD), let a be one of the factors, then b = LCM * GCD / a. Test if gcd(a, b) = the required gcd, if so calculate the sum a + b, then find the minimum among the sums, and you are done.
Trying to solve this problem with recursion and memoization but for input 7168 I'm getting wrong answer.
public int numSquares(int n) {
Map<Integer, Integer> memo = new HashMap();
List<Integer> list = fillSquares(n, memo);
if (list == null)
return 1;
return helper(list.size()-1, list, n, memo);
}
private int helper(int index, List<Integer> list, int left, Map<Integer, Integer> memo) {
if (left == 0)
return 0;
if (left < 0 || index < 0)
return Integer.MAX_VALUE-1;
if (memo.containsKey(left)) {
return memo.get(left);
}
int d1 = 1+helper(index, list, left-list.get(index), memo);
int d2 = 1+helper(index-1, list, left-list.get(index), memo);
int d3 = helper(index-1, list, left, memo);
int d = Math.min(Math.min(d1,d2), d3);
memo.put(left, d);
return d;
}
private List<Integer> fillSquares(int n, Map<Integer, Integer> memo) {
int curr = 1;
List<Integer> list = new ArrayList();
int d = (int)Math.pow(curr, 2);
while (d < n) {
list.add(d);
memo.put(d, 1);
curr++;
d = (int)Math.pow(curr, 2);
}
if (d == n)
return null;
return list;
}
I'm calling like this:
numSquares(7168)
All test cases pass (even complex cases), but this one fails. I suspect something is wrong with my memoization but cannot pinpoint what exactly. Any help will be appreciated.
You have the memoization keyed by the value to be attained, but this does not take into account the value of index, which actually puts restrictions on which powers you can use to attain that value. That means that if (in the extreme case) index is 0, you can only reduce what is left with one square (1²), which rarely is the optimal way to form that number. So in a first instance memo.set() will register a non-optimal number of squares, which later will get updated by other recursive calls which are pending in the recursion tree.
If you add some conditional debugging code, you'll see that map.set is called for the same value of left multiple times, and with differing values. This is not good, because that means the if (memo.has(left)) block will execute for cases where that value is not guaranteed to be optimal (yet).
You could solve this by incorporating the index in your memoization key. This increases the space used for memoization, but it will work. I assume you can work this out.
But according to Lagrange's four square theorem every natural number can be written as the sum of at most four squares, so the returned value should never be 5 or more. You can shortcut the recursion when you get passed that number of terms. This reduces the benefit of using memoization.
Finally, there is a mistake in fillSquares: it should add n itself also when it is a perfect square, otherwise you'll not find solutions that should return 1.
Not sure about your bug, here is a short dynamic programming Solution:
Java
public class Solution {
public static final int numSquares(
final int n
) {
int[] dp = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0;
for (int i = 1; i <= n; i++) {
int j = 1;
int min = Integer.MAX_VALUE;
while (i - j * j >= 0) {
min = Math.min(min, dp[i - j * j] + 1);
++j;
}
dp[i] = min;
}
return dp[n];
}
}
C++
// Most of headers are already included;
// Can be removed;
#include <iostream>
#include <cstdint>
#include <vector>
#include <algorithm>
// The following block might slightly improve the execution time;
// Can be removed;
static const auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
}();
#define MAX INT_MAX
using ValueType = std::uint_fast32_t;
struct Solution {
static const int numSquares(
const int n
) {
if (n < 1) {
return 0;
}
static std::vector<ValueType> count_perfect_squares{0};
while (std::size(count_perfect_squares) <= n) {
const ValueType len = std::size(count_perfect_squares);
ValueType count_squares = MAX;
for (ValueType index = 1; index * index <= len; ++index) {
count_squares = std::min(count_squares, 1 + count_perfect_squares[len - index * index]);
}
count_perfect_squares.emplace_back(count_squares);
}
return count_perfect_squares[n];
}
};
int main() {
std::cout << std::to_string(Solution().numSquares(12) == 3) << "\n";
return 0;
}
Python
Here we can simply use lru_cache:
class Solution:
dp = [0]
#functools.lru_cache
def numSquares(self, n):
dp = self.dp
while len(dp) <= n:
dp += min(dp[-i * i] for i in range(1, int(len(dp) ** 0.5 + 1))) + 1,
return dp[n]
Here are LeetCode's official solutions with comments:
Java: DP
class Solution {
public int numSquares(int n) {
int dp[] = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
// bottom case
dp[0] = 0;
// pre-calculate the square numbers.
int max_square_index = (int) Math.sqrt(n) + 1;
int square_nums[] = new int[max_square_index];
for (int i = 1; i < max_square_index; ++i) {
square_nums[i] = i * i;
}
for (int i = 1; i <= n; ++i) {
for (int s = 1; s < max_square_index; ++s) {
if (i < square_nums[s])
break;
dp[i] = Math.min(dp[i], dp[i - square_nums[s]] + 1);
}
}
return dp[n];
}
}
Java: Greedy
class Solution {
Set<Integer> square_nums = new HashSet<Integer>();
protected boolean is_divided_by(int n, int count) {
if (count == 1) {
return square_nums.contains(n);
}
for (Integer square : square_nums) {
if (is_divided_by(n - square, count - 1)) {
return true;
}
}
return false;
}
public int numSquares(int n) {
this.square_nums.clear();
for (int i = 1; i * i <= n; ++i) {
this.square_nums.add(i * i);
}
int count = 1;
for (; count <= n; ++count) {
if (is_divided_by(n, count))
return count;
}
return count;
}
}
Java: Breadth First Search
class Solution {
public int numSquares(int n) {
ArrayList<Integer> square_nums = new ArrayList<Integer>();
for (int i = 1; i * i <= n; ++i) {
square_nums.add(i * i);
}
Set<Integer> queue = new HashSet<Integer>();
queue.add(n);
int level = 0;
while (queue.size() > 0) {
level += 1;
Set<Integer> next_queue = new HashSet<Integer>();
for (Integer remainder : queue) {
for (Integer square : square_nums) {
if (remainder.equals(square)) {
return level;
} else if (remainder < square) {
break;
} else {
next_queue.add(remainder - square);
}
}
}
queue = next_queue;
}
return level;
}
}
Java: Most efficient solution using math
Runtime: O(N ^ 0.5)
Memory: O(1)
class Solution {
protected boolean isSquare(int n) {
int sq = (int) Math.sqrt(n);
return n == sq * sq;
}
public int numSquares(int n) {
// four-square and three-square theorems.
while (n % 4 == 0)
n /= 4;
if (n % 8 == 7)
return 4;
if (this.isSquare(n))
return 1;
// enumeration to check if the number can be decomposed into sum of two squares.
for (int i = 1; i * i <= n; ++i) {
if (this.isSquare(n - i * i))
return 2;
}
// bottom case of three-square theorem.
return 3;
}
}
I want to optimize this program. Currently my program is working slow because functions in the program are very much dependent on other functions in the program. What is the best way to optimize this?
public class MyClass {
public static void main(String args[]) {
int[] testValues = {3, 5, 10};
for (int i = 0; i < testValues.length; ++i) {
System.out.println(first(testValues[i]));
}
}
public static int first(int a) {
int b;
if (a <= 1) {
if (a == 1) {
b = convertOne(a);
} else {
b = convertTwo(a - 1);
}
} else {
return next(a);
}
return b;
}
public static int convertOne(int c) {
return++c;
}
public static int convertTwo(int d) {
int i = 1;
for (i = d * 11; i > d; i--) {
i--;
}
return i;
}
public static int next(int e) {
int container = first(e - 1);
return container + first(e - 2);
}
}
As I suspected, this is some kind of joke or code-golf puzzle. The function is a kind of Fibonacci function with -11 and 2 as the first terms.
The first method refactors to:
public static int first(int a) {
if (a <= 0) {
return (a - 1) * 11;
}
if (a == 1) {
return 2;
}
int n0 = -11;
int n1 = 2;
for (int i = 2; i <= a; i++) {
int t = n0 + n1;
n0 = n1;
n1 = t;
}
return n1;
}
All the rest is junk, or more likely, deliberate obfuscation.
1) One golden rule is; try to avoid Nesting as much as possible.
if (a <= 1) {
if (a == 1) {
b = convertOne(a);
} else {
b = convertTwo(a - 1);
}
} else {
return next(a);
}
2) You have used i-- twice, if its required do it like i-=2 in a loop.
public static int convertTwo(int d) {
int i = 1;
for (i = d * 11; i > d; i--) {
i--;
}
return i;
}
3) Following code is executing inadequate logic.
if (a <= 1) {
if (a == 1) {
b = convertOne(a);
} else {
b = convertTwo(a - 1);
}// this else is executing for cases < 1, but logic of "convertTwo(a - 1)" is ambiguous, try dry running it for -1
} else {
return next(a);
}
4) Logic of following code also does not need to be in function
public static int convertOne(int c) {
return ++c;
}
5) Functions are used to perform single reusable operation. In your next(int e) function you are doing nothing single. Do this in the first(int a) method.
I am totally a beginner learning a subject called Algorithms and Data Structures and got to the part about Big-O Notation. I have read many different materials writing about this but most of them just show examples of calculation of simple cases.
The assignment for this topic has some really interesting complex examples with recursion calling each other and for loops, while loops, etc...which I could not figure out and need help on calculating. I really appreciate any help and explanation, to understand deeply about this.
Also:
Ex No.3: I don't understand what the meaning of return "0xCAFE + 0xBABE + s"? I couldn't see it appear anywhere in the method, really strange to me.
Ex No.4: At first I thought these are different examples but I notice in method g has a call for method f so it should be in one example, is my assumption correct?
1.
long c(int x) {
if (x <= 1) {
return 1;
} else {
long s = 0;
for (int i = 1; i < x; i++) {
s = s + c(x - 1);
}
return s;
}
}
2.
long d(int x) {
long s = -x * x;
while (s <= x * x * x) {
s++;
}
for (long i = s * x; i > 0; i--) {
s--;
}
return s;
}
3.
double e(long x, long y) {
double s = 0_0;
for (int i = 1; i <= x; i *= 2) {
for (double j = x; j >= 1; j /= 3) {
for (int k = 0; k < y; k += 4) {
s++;
}
}
}
return 0xCAFE + 0xBABE + s;
}
4.Calculate each f & g
long f(int x, int y) {
if (x <= 0) {
return y;
} else {
return f(x - 1, 2 * y);
}
}
double g(int x, int y) {
double s = 0.0D;
for (long i = f(x, y); i >= 0; i--) {
s++;
}
return s;
}
5.
char h(int x) {
char h = 'h';
for (long i = h; i-- > ++i; x--) {
h++;
}
return h;
}
Big-O is just a way to measure the Runtime it takes for algorithms to complete.
You should look at the base of how to understand this before you try to understand these examples because they're rather complex.
A small example: O(n)
public void o(int n, int i) {
if (i == n)
return;
o(n, i++);
}
This resembles a for loop,
for (int i = 0; i <= n; i++)
In example 3:
return 0xCAFE + 0xBABE + s;
Is arbitrary, it looks like it doesn't represent anything and 's' will be the big O value for the methods complexity through its loops,
for (int i = 1; i <= x; i *= 2) { // BigO = 2 ^ i
for (double j = x; j >= 1; j /= 3) { // BigO = (2 ^i) / 3
for (int k = 0; k < y; k += 4) { //BigO = y / 4
Here is my implementation of the fibonacci sequence using java
/**
* Returns nth fibonacci number
*/
public class fib {
public static void main(String[] args){
System.out.println(fibonacci(12));
}
public static int fibonacci(int n) {
if (n == 0){
return 0;
} else if (n == 1){
return 1;
} else {
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
}
But visualization of this method using recursion made me think it would be a lot faster.
Here is a visualization of fib(5). http://imgur.com/a/2Rgxs
But this got my thinking, notice at the bottom when we bubble up from the bottom of the recursive path we calculate fib(2), fib(3) and fib(4) but then we recalculate fib(3) on the very top right branch. So I was thinking when we are bubbling back up why not save fib(3) calculated from the left branch so we don't do any calculations on the right branch like my method currently does, like a hashtable while coming back up.
My question is, how do I implement this idea?
When you want to add the HashMap and stay with your original approach, try this:
static HashMap<Integer, Integer> values = new HashMap<Integer, Integer>();
public static void main(String[] args){
values.put(0, 0);
values.put(1, 1);
System.out.println(fibonacci(12));
}
public static int fibonacci(int n) {
if (values.containsKey(n)){
return values.get(n);
} else {
int left = values.containsKey(n - 1) ? values.get(n - 1) : fibonacci(n - 1);
values.put(n - 1, left);
int right = values.containsKey(n - 2) ? values.get(n - 2) : fibonacci(n - 2);
values.put(n - 2, right);
return left + right;
}
}
This approach could be very fast if you call it more often because the fibonacci results are already stored in the values (for sure this could also be done with other approaches):
public static void main(String[] args){
values.put(0, 0);
values.put(1, 1);
System.out.println(fibonacci(12));
System.out.println(fibonacci(11));
System.out.println(fibonacci(10));
}
For a fast calculation, you do not need recursion at all - just shift the intermediate results
public static int fibonacci(int n) {
if (n == 0) {
return 0;
} else {
int npp = 0; // pre-previous number
int np = 1; // previouse number
int r = 1; // current number, eventually the result
for (int i = 2; i <= n; i++) {
r = np + npp;
npp = np;
np = r;
}
return r;
}
}
In order to avoid repeated calculations, you can use dynamic programming. BTW, this is not a memory optimized solution, but it can be faster than the recursive one.
public static int fibonacci(int n)
{
int f[] = new int[n+1];
for (int i = 0; i <= n; i++) {
if(i == 0 || i == 1) {
f[i] = i;
}
else {
f[i] = f[i-1] + f[i-2];
}
}
return f[n];
}