package com.freetymekiyan.algorithms.level.medium; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; /** * Given a positive integer num, write a function which returns True if num is a perfect square else False. * <p> * Note: Do not use any built-in library function such as sqrt. * <p> * Example 1: * <p> * Input: 16 * Returns: True * Example 2: * <p> * Input: 14 * Returns: False * <p> * Company Tags: LinkedIn * Tags: Binary Search, Math * Similar Problems: (M) Sqrt(x) */ public class ValidPerfectSquare { private ValidPerfectSquare v; /** * Binary Search. * The original thought is binary search from 1 to sqrt(n). * Since we cannot use built-in library, we use n / 2 to replace it. * Note that n / 2 > sqrt(n) when n > 4. * The initial range is from 1 to num / 2. * For each middle value m, compare t = m * m and num. * | If t == num, return true. * | If t > num, m is too big, reduce upper bound r = m - 1. * | If t < num, m is too small, increase lower bound l = m + 1. * Return false if search failed. */ public boolean isPerfectSquare(int num) { if (num < 4) { return num == 1; } int lo = 1; int hi = num / 2; while (lo <= hi) { long mid = lo + (hi - lo) / 2; long t = mid * mid; // Might overflow. num = 808021. if (t == num) { return true; } else if (t > num) { hi = (int) mid - 1; } else { lo = (int) mid + 1; } } return false; } /** * Math. * A perfect square is the sum of a consecutive odd number sequence. * 1 + 3 + 5 + 7 + 9 ... * For example: 1 = 1, 4 = 1 + 3, 9 = 1 + 3 + 5, 16 = 1 + 3 + 5 + 7 */ public boolean isPerfectSquareB(int num) { int i = 1; while (num > 0) { num -= i; i += 2; } return num == 0; } /** * Math, Newton's Method. * x(n+1) = x(n) - f(x(n)) / f'(x(n)) * Find the root for y = num - t^2. * t - (num - t^2) / -2t = t + num / 2t - t / 2 = (t + num / t) / 2 * https://en.wikipedia.org/wiki/Newton%27s_method */ public boolean isPerfectSquareC(int num) { long t = num; while (t * t > num) { t = (t + num / t) / 2; } return t * t == num; } @Before public void setUp() { v = new ValidPerfectSquare(); } @Test public void testExamples() { int num = 16; Assert.assertTrue(v.isPerfectSquare(num)); Assert.assertTrue(v.isPerfectSquareB(num)); Assert.assertTrue(v.isPerfectSquareC(num)); num = 14; Assert.assertFalse(v.isPerfectSquare(num)); Assert.assertFalse(v.isPerfectSquareB(num)); Assert.assertFalse(v.isPerfectSquareC(num)); num = 1; Assert.assertTrue(v.isPerfectSquare(num)); Assert.assertTrue(v.isPerfectSquareB(num)); Assert.assertTrue(v.isPerfectSquareC(num)); num = 2; Assert.assertFalse(v.isPerfectSquare(num)); Assert.assertFalse(v.isPerfectSquareB(num)); Assert.assertFalse(v.isPerfectSquareC(num)); num = 3; Assert.assertFalse(v.isPerfectSquare(num)); Assert.assertFalse(v.isPerfectSquareB(num)); Assert.assertFalse(v.isPerfectSquareC(num)); num = 4; Assert.assertTrue(v.isPerfectSquare(num)); Assert.assertTrue(v.isPerfectSquareB(num)); Assert.assertTrue(v.isPerfectSquareC(num)); num = 5; Assert.assertFalse(v.isPerfectSquare(num)); Assert.assertFalse(v.isPerfectSquareB(num)); Assert.assertFalse(v.isPerfectSquareC(num)); num = 808201; Assert.assertTrue(v.isPerfectSquare(num)); Assert.assertTrue(v.isPerfectSquareB(num)); Assert.assertTrue(v.isPerfectSquareC(num)); } @After public void tearDown() { v = null; } }