算法小结(Math)

Math

题目:453. Minimum Moves to Equal Array Elements

Given a non-empty integer array of size n, find the minimum number of moves required to make all array elements equal, where a move is incrementing n - 1 elements by 1.

Example:
Input:
[1,2,3]
Output:
3
Explanation:
Only three moves are needed (remember each move increments two elements):
[1,2,3] => [2,3,3] => [3,4,3] => [4,4,4]

    public int minMoves(int[] nums) {
        long sum = 0;
        int min = nums[0];
        for (int n : nums){
            if (n < min){
                min = n;
            }
            sum += n;
        }
        return (int) sum - min * nums.length;
    }
}

思路: sum 和 ;n 长度 ; m 增加次数 ;x 增加最大值;
sum + m * (n-1) = x * n ;
x = minNum + m ;
m = sum - n*minNum;

题目:462. Minimum Moves to Equal Array Elements II

要求:每一步进加减一操作,数组相等
思路:数组sort,涉及到数组很多都会用到这个。大的减去小的,设最终结果为x,那么(big - x)+ (x - small) = big - small;
使用quick select可以快速找到中位数
最优:quick select (注意几个边界以及bugfree)

题目 441. Arranging Coins

思路:主要是数学方法 n*(n+1)/2 以及解二元一次方程 可以使用二分查找,但是最优解
n = 8

The coins can form the following rows:
¤
¤ ¤
¤ ¤ ¤
¤ ¤

题目 423. Reconstruct Original Digits from English

给随机字符串,输出数字string例如,fvie fuor 输出45
1刷无思路
思路:这个有个outbox的想法,取出每个数字唯一的字母,进行计数。对于多出的,可以直接进行统计相减去

题目:372. Super Pow

要求: Your task is to calculate ab mod 1337 where a is a positive integer and b is an extremely large positive integer given in the form of an array.
思路:公式:a * b % c = (a%c) * (b % c) % c;
也是用到了递归的方法。

public class Solution {
    private int base = 1337;
    public int superPow(int a, int[] b) {
        if (b.length == 0){
            return 1;
        }
        int last = b[b.length - 1];
        int [] array = Arrays.copyOf(b, b.length - 1);
        return powMod(superPow(a, array), 10) * powMod(a, last) % base;
    }
    private int powMod(int a, int n){
        a %= base;
        int res = 1;
        for (int i = 0; i < n; i++){
            res = (res * a) % base;
        }
        return res;
    }
}
题目:43. Multiply Strings

要求:两个数字字符串相乘
思路:传统乘法
一刷:

public class Solution {
     public   String multiply(String num1, String num2) {
            if (num1.equals("0") || num2.equals("0")){
                return "0";
            }
            int [][] result = new int[num2.length()][num1.length() + 1];
            int carry = 0, i = 0, j = 0, temp =0 , x, y;
            while (i < num2.length() ){
                x = num2.charAt(num2.length() - i - 1) - '0';
                carry = 0;
                temp = 0;
                result[i][num1.length()] = 0;
                j = 0;
                while (j < num1.length() || carry != 0 ){
                    y = (j == num1.length() ? 0 : (num1.charAt(num1.length() - j - 1) - '0'));
                    temp = x * y + carry;
                    result[i][j] = temp % 10;
                    carry = temp / 10;
                    j++;
                }
                i++;
            } 
            return addString(result);
        }
        public   String addString(int [][] result ){
            StringBuffer sb = new StringBuffer();
            int temp = 0, carry = 0, i = 0;  
            while (i < result.length + result[0].length || carry != 0){
                if (i ==  result.length + result[0].length ){
                    sb.append(carry);
                    break;
                }
                temp = carry;
                for (int j = 0 ; j <= i && j < result.length; j++ ){
                    if (i - j >= result[0].length ){
                        continue;
                    }
                    temp += result[j][i - j];
                }
                sb.append( temp % 10 );
                carry = temp / 10;
                i++;
            }
            String nums = sb.reverse().toString();
            int j = 0;
            for (; j < i ;j++){
                if( nums.charAt(j) != '0'){
                    break;
                }
            }
            return nums.substring(j, nums.length());
        }
}

效率低下
最优解:

`num1[i] * num2[j]` will be placed at indices `[i + j`, `i + j + 1]` 
public class Solution {
    public String multiply(String num1, String num2) {
        int m = num1.length();
        int n = num2.length();
        int [] pos = new int[m + n];
        int temp = 0;
        int p1 = 0;
        int p2 = 0;
        int num = 0;
        for (int i = m - 1; i >= 0; i--){
            for (int j = n - 1; j >= 0; j--){
                temp = (num1.charAt(i) - '0') * (num2.charAt(j) - '0');
                p1 = i + j;
                p2 = p1 + 1;
                num = temp + pos[p2];
                pos[p1] += num / 10;
                pos[p2] = num % 10;
            }
        }
        StringBuilder sb = new StringBuilder();
        for (int p : pos){
            if (!(sb.length() == 0 && p == 0)) {sb.append(p); }
        }     
        return sb.length() == 0 ? "0" : sb.toString();
    }
}
题目:69. Sqrt(x)

要求:对整数开根号
一刷,最优解,二分法查找:

public class Solution {
    public int mySqrt(int x) {
        // binary search
        if (x == 0){
            return 0;
        }
        int left = 1, right = x, mid;
        while (true){
            mid = left + ((right - left) >> 1);
            if (mid  > x / mid){
                right = mid - 1;
            } else {
                if (mid + 1 > x / (mid + 1)){
                    return mid;
                }
                left = mid + 1;
            }
        }
    }
}
题目:29. Divide Two Integers

要求:Divide two integers without using multiplication, division and mod operator.
If it is overflow, return MAX_INT.
被除数除以除数,dividend / divisor
思路:采用位操作

public class Solution {
   public int divide(int dividend, int divisor) {
    //Reduce the problem to positive long integer to make it easier.
    //Use long to avoid integer overflow cases.
    int sign = 1;
    if ((dividend > 0 && divisor < 0) || (dividend < 0 && divisor > 0))
        sign = -1;
    long ldividend = Math.abs((long) dividend);
    long ldivisor = Math.abs((long) divisor);

    //Take care the edge cases.
    if (ldivisor == 0) return Integer.MAX_VALUE;
    if ((ldividend == 0) || (ldividend < ldivisor)) return 0;

    long lans = ldivide(ldividend, ldivisor);

    int ans;
    if (lans > Integer.MAX_VALUE){ //Handle overflow.
        ans = (sign == 1)? Integer.MAX_VALUE : Integer.MIN_VALUE;
    } else {
        ans = (int) (sign * lans);
    }
    return ans;
}

private long ldivide(long ldividend, long ldivisor) {
    // Recursion exit condition
    if (ldividend < ldivisor) return 0;

    //  Find the largest multiple so that (divisor * multiple <= dividend), 
    //  whereas we are moving with stride 1, 2, 4, 8, 16...2^n for performance reason.
    //  Think this as a binary search.
    long sum = ldivisor;
    long multiple = 1;
    while ((sum+sum) <= ldividend) {
        sum += sum;
        multiple += multiple;
    }
    //Look for additional value for the multiple from the reminder (dividend - sum) recursively.
    return multiple + ldivide(ldividend - sum, ldivisor);
}
}
题目:2. Add Two Numbers

要求:对链表中的数据进行依次的加法
一刷:bugfree
最优解:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode ln1 = l1, ln2 = l2, head = null, node = null;
        int carry = 0, remainder = 0, sum = 0;
        head = node = new ListNode(0);

        while(ln1 != null || ln2 != null || carry != 0) {
            sum = (ln1 != null ? ln1.val : 0) + (ln2 != null ? ln2.val : 0) + carry;
            carry = sum / 10;
            remainder = sum % 10;
            node = node.next = new ListNode(remainder);
            ln1 = (ln1 != null ? ln1.next : null);
            ln2 = (ln2 != null ? ln2.next : null);
        }
        return head.next;
    }
}
题目365. Water and Jug Problem

要求:You are given two jugs with capacities x and y litres. There is an infinite amount of water supply available. You need to determine whether it is possible to measure exactly z litres using these two jugs.
If z liters of water is measurable, you must have z liters of water contained within one or both buckets by the end.
思路:一刷无思路,主要是应用数学公式,在数论中,裴蜀定理是一个关于最大公约数(或最大公约式)的定理。x 与 y 的最小公约数a,z可对a求余即可。

public class Solution {
    public boolean canMeasureWater(int x, int y, int z) {
        if (x + y < z) return false;
        if (x == z || y == z || x + y == z) return true;
        return z % getGCD(x, y) == 0;
    }
    public int getGCD(int a, int b){
        int temp = 0;
        while (b != 0){
            temp = b;
            b = a % b;
            a = temp;
        }
        return a;
    }
}
题目:367. Valid Perfect Square

要求:Given a positive integer num, write a function which returns True if num is a perfect square else False.
Note: Do not use any built-in library function such as sqrt.
给一个非负的数,判断是否存在平方根。
思路:二分法
一刷:没ac,在处理 int * int 的数的时候,无法给出越界的处理,用 long来处理。
最优解:

public class Solution {
    public boolean isPerfectSquare(int num) {
        int left = 1, right = num;
        long mid = 0;
        while (left <= right){
            mid = left + ((right - left) >> 1);
            if (mid * mid > num ){
                right = (int) mid - 1;
            } else if (mid * mid  == num){
                return true;
            } else {
                left = (int) mid + 1;
            }
        }
        return false;
    }
}
题目:368. Largest Divisible Subset

Given a set of distinct positive integers, find the largest subset such that every pair (Si, Sj) of elements in this subset satisfies: Si % Sj = 0 or Sj % Si = 0.
If there are multiple solutions, return any subset is fine.
要求:给一组数 例如 1 2 4 7 8,返回可以完全求余的list,这个就返回 1 2 4 8.
思路:这个属于DP问题,先对数组进行排序处理,子状态的定义为:以数组的每一位结尾的最长可被约分子串的长度,然后得到最长长度的索引,依照前面的pre数组的存储,进行逆序添加。
一刷:无思路
最优解:

public class Solution {
    public List<Integer> largestDivisibleSubset(int[] nums) {
        int n = nums.length;
        int[] count = new int[n];
        int[] pre = new int[n];
        Arrays.sort(nums);
        int max = 0, index = -1;
        for (int i = 0; i < n; i++) {
            count[i] = 1;
            pre[i] = -1;
            for (int j = i - 1; j >= 0; j--) {
                if (nums[i] % nums[j] == 0) {
                    if (1 + count[j] > count[i]) {
                        count[i] = count[j] + 1;
                        pre[i] = j;
                    }
                }
            }
            if (count[i] > max) {
                max = count[i];
                index = i;
            }
        }
        List<Integer> res = new ArrayList<>();
        while (index != -1) {
            res.add(nums[index]);
            index = pre[index];
        }
        return res;
    }
}

动态规划的n*log(n),最长递增子序列,这个temp[i]表示的是组成的长度为i + 1的子序列中的list的最小的数,然后再用二分查找进行插入处理,insert函数用于维护temp,并且返回当新的数据进入以后,数组长度end是否发生变化,后来的数据如果大与结尾,就延长长度,如果不是,替换到合适的位置,使得temp[i]一直为长度为i + 1的右边最小的值,每次更新检查end变化,虽然这样能拿到长度,但是取不出来数据。

 public static int getlong(int [] nums){
        int len = nums.length;
        int []  temps = new int[len];
        temps[0] = nums[0];
        int end = 0, max = -1;
        for (int i = 1; i < len; i++){
            end = insert(temps,end,nums[i]);
            if (end > max){
                max = end;
            }
        }
        return max + 1;
    }
    public static int insert(int [] temps ,int end, int value){
        if (value >= temps[end]){
            temps[end + 1] = value;
            return end + 1;
        }
        int left = 0;
        int right = end;
        int mid = -1;
        if (end == 0){
            if (temps[end] > value){
                temps[end] = value;
                return end;
            }
        }
        while(true){
            mid = left + ((right - left) >> 1);
            if (temps[mid] > value){
                right = mid - 1;
            }else {
                if (temps[mid + 1] >= value ){
                    temps[mid + 1] = value;
                    break;
                } else {
                    left = mid + 1;
                }
            }
        }
        return end;
    }
题目:335. Self Crossing

You are given an array x of n positive numbers. You start at point (0,0) and moves x[0] metres to the north, then x[1] metres to the west, x[2] metres to the south, x[3] metres to the east and so on. In other words, after each move your direction changes counter-clockwise.
要求:输入的是一个数组,按照顺序以逆时针为方向延长,检测能否穿过自身。
思路:共有三种情况,1.第四条穿过第一条,第五条穿过第二条。。。
2.第五条与第二条重合,第六条与第三条重合。。。
3.第六条穿过第一条,第七条穿过第二条。。
程序:第一道hard的题目

public class Solution {
    public boolean isSelfCrossing(int[] x) {
        int len = x.length;
        if (len < 4){
            return false;
        }
        for (int i = 3; i < len; i++){
            if (x[i - 1] <= x[i - 3] && x[i] >= x[i - 2]){
                return true;
            }
            if (i >= 4 && x[i - 1] == x[i - 3] && x[i] >= x[i - 2] - x[i - 4]){
                return true;
            }
            if (i >= 5 && x[i - 2] >= x[i - 4] && x[i] >= x[i - 2] - x[i - 4] && x[i - 1] <= x[i - 3] 
                && x[i - 1] >= x[i - 3] - x[i - 5]){
                    return true;
            }
        }
        return false;
    }
}
题目313. Super Ugly Number

要求: Write a program to find the nth super ugly number.

Super ugly numbers are positive numbers whose all prime factors are in the given prime list primes of size k. For example, [1, 2, 4, 7, 8, 13, 14, 16, 19, 26, 28, 32] is the sequence of the first 12 super ugly numbers given primes = [2, 7, 13, 19] of size 4.
思路:题目并没有看懂,然后就直接写别人的答案

public class Solution {
   public int nthSuperUglyNumber(int n, int[] primes) {
        int[] ugly = new int[n];
        int[] idx = new int[primes.length];
        int[] val = new int[primes.length];
        Arrays.fill(val, 1);

        int next = 1;
        for (int i = 0; i < n; i++) {
            ugly[i] = next;

            next = Integer.MAX_VALUE;
            for (int j = 0; j < primes.length; j++) {
                //skip duplicate and avoid extra multiplication
                if (val[j] == ugly[i]) val[j] = ugly[idx[j]++] * primes[j];
                //find next ugly number
                next = Math.min(next, val[j]);
            }
        }

        return ugly[n - 1];
    }

}
题目:12. Integer to Roman

要求:将一个1-3999的整数用罗马数字进行表述,
思路:按照罗马数字的规律,采用StringBuilder的数据结构。
代码:

public class Solution {
    public String intToRoman(int num) {
        int[] values = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
        String[] strs = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < values.length; i++) {
            while (num >= values[i]) {
                num -= values[i];
                sb.append(strs[i]);
            }
        }
        return sb.toString();
    }
}
题目:279. Perfect Squares

要求: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.
思路:提示采用三种思路,1.DP 2.BreadthfirstSearch 3.math
解法1:DP,从1一直到n进行计算,数组记录result计算结果,在计算第m个值时,需要对m以前的值进行迭代,求出最小的result[m - j * j] + 1,记入result[m]。

public class Solution {
    public int numSquares(int n) {
        int[] cntCountPrefect  = new int[n + 1];
        //static DP
        cntCountPrefect[0] = 0;
        int temp = Integer.MAX_VALUE;
        for (int i = 1; i <= n; i++){
            // stctic
            temp = Integer.MAX_VALUE;
            for (int j = 1; j * j <= i; j++){
                temp = Math.min(temp, cntCountPrefect[i - j * j] + 1);
            }
            cntCountPrefect[i] = temp;
        }
        return cntCountPrefect[n];
    }
}

解法2:最优解,拉格朗日四平方定理

public class Solution {
    public int numSquares(int n) {
         // 拉格朗日的四方定理
         if (isSquares(n)){
             return 1;
         }
        // The result is 4 if and only if n can be written in the 
        // form of 4^k*(8*m + 7). Please refer to 
        // Legendre's three-square theorem.
         while ((n & 3) == 0){// n % 4 == 0
             n >>= 2;
         }
         if ((n & 7) == 7){// n % 8 == 7
             return 4;
         }
         for (int i = 1; i <= Math.sqrt(n); i++){
             if (isSquares(n - i * i)){
                 return 2;
             }
         }
        return 3;
    }
    public boolean isSquares(int n){
        int m = (int) Math.sqrt(n);
        return m * m == n ? true:false;
    }
}
题目:166. Fraction to Recurring Decimal

要求:Given two integers representing the numerator and denominator of a fraction, return the fraction in string format.

If the fractional part is repeating, enclose the repeating part in parentheses.

For example,

Given numerator = 1, denominator = 2, return “0.5”.
Given numerator = 2, denominator = 1, return “2”.
Given numerator = 2, denominator = 3, return “0.(6)”.
求分数的值。
思路:需要用map记录下小数点后第一次出现重复的index。目前最优解:

public class Solution {
    public String fractionToDecimal(int numerator, int denominator) {
        if (numerator == 0){
            return "0";
        }
        StringBuilder sb = new StringBuilder();
        sb.append(((numerator > 0) ^ (denominator > 0)) ? "-" : "");
        long num = Math.abs((long) numerator);
        long den = Math.abs((long) denominator);
        //zheng shu
        sb.append(num / den);
        num %= den;
        if (num == 0){
            return sb.toString();
        }
        //xiaoshu
        sb.append(".");
        Map<Long, Integer> map = new HashMap<Long, Integer>();
        map.put(num, sb.length());
        while (num != 0){
            num *= 10;
            sb.append(num / den);
            num %= den;
            if (map.containsKey(num)){
                int index = map.get(num);
                sb.insert(index, "(");
                sb.append(")");
                break;
            } else {
                map.put(num, sb.length());
            }
        }
        return sb.toString();
    }
}
题目50. Pow(x, n)

要求:Implement pow(x, n).
思路:对指数进行减半,然后递归实现。
代码:

public class Solution {
    public double myPow(double x, int n) {
        long nn = (long) n;
        if (nn == 0){
            return 1;
        }
        if (nn < 0){
            x = 1 / x;
            nn = -nn;
        }
        return (nn % 2 == 0) ? myPow(x * x, (int) (nn / 2)) : x * myPow(x * x, (int) (nn / 2));
    }
}
题目:264. Ugly Number II

要求:Write a program to find the n-th ugly number.
Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers.
Note that 1 is typically treated as an ugly number, and n does not exceed 1690.找到并返回第n个丑数。
思路:利用动态规划,记录下需要返回的值
解法:

public class Solution {
    public int nthUglyNumber(int n) {
        if (n == 1){
            return 1;
        }
        int t2 = 0, t3 = 0, t5 = 0;//pointer
        int [] temp = new int[n + 1];
        temp[0] = 1;
        for (int i = 1; i < n; i++){
            temp[i] = Math.min(temp[t2] * 2, Math.min(temp[t3] * 3, temp[t5] * 5));
            if (temp[i] == temp[t2] * 2){
                t2++;
            }
            if (temp[i] == temp[t3] * 3){
                t3++;
            } 
            if (temp[i] == temp[t5] * 5){
                t5++;
            }
        }
        return temp[n - 1];
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值