数学问题归纳

2. 两数相加(加法模板 + 链表操作)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        /**
        分析:
        一般思路是将两个链表转换为数字,数字相加,得到答案,然后将答案逆序放回链表中.
        经过思考后,发现实现十分麻烦,不如直接将链表的对应数组相加,然后判断有无进位。
        这是一道加法模板题,只不过场景换成了链表
         */
         // 定义一个结果链表(有点像伪头部法)
         ListNode res = new ListNode();
         // 定义一个工作节点,指向首节点
         ListNode cur = res;
         // 默认进位为 0
         int carry = 0; 
         while(l1 != null || l2 != null){
             // 定义对应数字
             int x = l1 == null ? 0 : l1.val;
             int y = l2 == null ? 0 : l2.val;
             int sum = x + y + carry;
             // 构造节点
             cur.next = new ListNode(sum % 10);
             // 更新进位
             carry = sum / 10;
             // 移动工作节点
             cur = cur.next;
             // 移动l1和l2
             // 一般而言为了避免空指针异常,都要进行异常判断
             if(l1 != null){
                l1 = l1.next;
             }
             if(l2 != null){
                l2 = l2.next;
             }
         }
         // 处理最后一个进位信息
         if(carry != 0){
             // 尾巴增加一个节点
             cur.next = new ListNode(carry);
         }
         // 返回结果
         return res.next;

    }
}

7. 整数反转

注:第一次自己写的代码(AC了,但是代码好丑啊),其实整体思路是没错的,转换成字符串,字符串比较好进行数字转换操作,更加进阶的操作是把字符串再转换成char数组,这样就可以进行原地修改啦!!!

class Solution {
    public int reverse(int x) {
        /**
        分析:
        将数字转换为字符串,然后再对字符串遍历,这里使用 long来进行存储,然后判断是否溢出。
        但是自己写的代码总感觉有点丑~~~可以再优化的尤其是判断正负这一块
         */
         if( x > 0){
             String temp = String.valueOf(x);
             long res = 0;
             for(int i = temp.length() - 1; i >= 0; i--){
                 res = res * 10 + (temp.charAt(i) - '0');
             }
             if( res > Math.pow(2,31) - 1){
                 return 0;
             }
             return (int)res;
         }else if(x < 0  ){
             String temp = String.valueOf(Math.abs(x));
             long res = 0;
             for(int i = temp.length() - 1; i >= 0; i--){
                 res = res * 10 + (temp.charAt(i) - '0');
             }
             if( res > Math.pow(2,31) ){
                 return 0;
             }
             return (int)-res;
         }
         return 0;

    }
}

注意:在第二种优化解法中,学到了符号的判断移动,数字型和字符串类型的调用转换,以及包装类中的MAX_VALUE和MIN_VALUE的用法!!!

class Solution {
    public int reverse(int x) {
        /**
        分析:
        将数字转换为字符串,然后再对字符串遍历,这里使用 long来进行存储,然后判断是否溢出。
        但是自己写的代码总感觉有点丑~~~可以再优化的尤其是判断正负这一块===》使用char数组吧!~
         */
        // 转换为字符串
        String str = String.valueOf(x);
        // 转换为char数组
        char[] temp = str.toCharArray();
        // 定义双指针
        int left = 0, right = temp.length - 1;
        if(temp[left] < '0' || temp[left] > '9'){
            // 排除负号的影响
            left++;
        }
        // 反转
        while(left < right){
            char t = temp[left];
            temp[left] = temp[right];
            temp[right] = t;
            left++;
            right--;
        }
        // 判断是否溢出
        long res = Long.parseLong(new String(temp));
        if(res > Integer.MAX_VALUE || res < Integer.MIN_VALUE){
            return 0;
        }
        return (int)res;

    }
}

9. 回文数(双指针)

class Solution {
    public boolean isPalindrome(int x) {
        /**
        很简单,就是双指针的应用。整数==》字符串==》字符数组(这一步也不是很需要,因为不涉及到原地修改操作)
         */
        String str = String.valueOf(x);
        char[] temp = str.toCharArray();
        int left = 0, right = temp.length - 1;
        while(left < right){
            if(temp[left] != temp[right]){
                return false;
            }
            left++;
            right--;
        }
        return true;

    }
}

43. 字符串相乘(有点难理解…)

class Solution {
    public String multiply(String num1, String num2) {
        /**
        分析:
        题干中要求,不能使用大数类型,并且不能直接将输入转换为整数。那么就提示我们只能一个一个处理数字了!
        首先得意识到这是一个数学问题,要去思考如何将数字的乘法进行分解。一个简单的思路是“加法”,num1乘以num2中的每个位置的数字,然后再累加,最后得到答案。算法执行过程中有很多细节需要注意。
        - 使用StringBuilder数据结构,这样可以动态修改
        - num2中除了最后一个数字,其它数字进行乘法时,后续要补0
        - 在处理乘法的时候,时刻注意进位carry的存在
         */
         // 特判
         if (num1.equals("0") || num2.equals("0")) return "0";

        String ans = "0";
        int m = num1.length();
        int n = num2.length();

        // 处理被乘数的每一位
        for (int i = n - 1; i >= 0; i--) {
            StringBuilder currAns = new StringBuilder();
            // 对当前位的后面补 0
            for (int j = n - 1; j > i; j--) currAns.append("0");

            int y = num2.charAt(i) - '0'; // 当前位的值
            int carry = 0;
            for (int j = m - 1; j >= 0; j--) {
                // 将当前位的值和乘数的每一位进行相乘
                int x = num1.charAt(j) - '0';
                int product = x * y + carry;
                currAns.append(product % 10);
                carry = product / 10;
            }
            if (carry != 0) currAns.append(carry);
            // 将被乘数每一位和乘数相乘的结果累加
            ans = addStrings(ans, currAns.reverse().toString());
        }
        return ans;
    }

    public String addStrings(String num1, String num2) {
        StringBuilder res = new StringBuilder();

        int i1 = num1.length() - 1, i2 = num2.length() - 1;
        int carry = 0;
        while (i1 >= 0 || i2 >= 0) {
            int x = i1 >= 0 ? num1.charAt(i1) - '0' : 0;
            int y = i2 >= 0 ? num2.charAt(i2) - '0' : 0;

            int sum = x + y + carry;
            res.append(sum % 10);
            carry = sum / 10;

            i1--;
            i2--;
        }
        if (carry != 0) res.append(carry);
        return res.reverse().toString();
    }
}

66. 加一(数学问题之特殊情况判别)

注意:本题的解法就是了解遇到10会进位,这个进位又和+1重复,所有可以使用遍历的方法

class Solution {
    public int[] plusOne(int[] digits) {
        /**
        分析:
        将这个数转换为数字,数字+1,然后数字再转换为数组.后来发现这个方法是可以的,但是代码十分臃肿,而且测试案例出错概率很大。
        不如进行数学分析!!!反向遍历数组 + 1,观察是否会达到10,不会达到那么就是直接return,会的话重新申请一个新的数组(数组长度+1)
         */
         for(int i = digits.length - 1; i >= 0 ; i--){
             digits[i]++;
             digits[i] %= 10;
             if(digits[i] != 0){
                 // 说明没有达到10,那么就直接return结果
                 return digits;
             }
         }
         // 遍历一圈结束后,没有return 则说明是99999类型的
         int[] temp = new int[digits.length + 1];
         temp[0] = 1;
         return temp;
    }
}

67. 二进制求和(加法模板)

注意:第一次没做出来(溢出了),但是学会了一个api,Integer.toBinaryString()

class Solution {
    public String addBinary(String a, String b) {
        /**
        分析:
        二进制求和就是将二进制转换为数字,然后数字相加,最后返回二进制.
        最后测试案例不通过,不过倒是学会一个api,java中整数转换为二进制字符串Integer.toBinaryString()
         */
         int sum = 0;
         sum = binaryToInt(a) + binaryToInt(b);
         return Integer.toBinaryString(sum);


    }
    public int binaryToInt(String a){
        int count = 0, sum = 0;
        for(int i = a.length() - 1; i >= 0; i--){
            if(a.charAt(i) == '1'){
                sum += Math.pow(2,count);
            }
            count++;
        }
        return sum;
    }
    // 本想自己写一个出来,发现这玩意太复杂,涉及底层源码
    // public String intToBinary(int sum){

    // }
}

注意:这种接法就是使用了加法模板!!!一定要有这种模板思维,不管多少进制,涉及到加法我都可以套用这个模板。

class Solution {
    public String addBinary(String a, String b) {
        /**
        分析:
        二进制求和就是将二进制转换为数字,然后数字相加,最后返回二进制.
        最后测试案例不通过,不过倒是学会一个api,java中整数转换为二进制字符串Integer.toBinaryString()
        本身二进制和十进制求和是一样的(只不过一个进制为2,一个进制为10),那么就可以套用加法模板
         */
         // 使用sb动态修改
         StringBuilder sb = new StringBuilder();
         int len1 = a.length() - 1, len2 = b.length() - 1;
         // 定义进位
         int carry = 0;
         while( len1 >= 0 || len2 >= 0){
             // 取数字
             int x = len1 < 0 ? 0 : a.charAt(len1) - '0';
             int y = len2 < 0 ? 0 : b.charAt(len2) - '0';
             int sum = x + y + carry;
             sb.append(sum % 2);
             carry = sum / 2;

             len1--;
             len2--;
         }
         // 最后判断进制
         if(carry != 0){
             sb.append(carry);
         }
         return sb.reverse().toString();

    }      
}

204. 计数质数(数学解法…)

注意:这里是暴力解法,算法超时了!!!

class Solution {
    public int countPrimes(int n) {
        // 使用暴力解法,结果超时了
        int count = 0;
        if(n == 0 || n== 1){
            return 0;
        }
        for(int i = 2; i < n; i++){
            if(isPrimes(i)){
                count++;
            }
        }
        return count;

    }
    public boolean isPrimes(int num){
        for(int i = 2; i  < num; i++){
            if(num % i == 0){
                return false;
            }
        }
        return true;
    }
}

注意:下面的解法可以通过测试案例,主要是运用一个标记数组,进行标记不可能是质数的数

class Solution {
    public int countPrimes(int n) {
        int ans = 0;
        // 默认全是质数
        boolean[] notPrimes = new boolean[n];
        for (int x = 2; x < n; x++) {
            // 不是质数就跳过循环
            if (notPrimes[x]) continue;
            // 是质数,就加1
            ans++;
            // 如果 x 是质数,那么 2x、3x、4x.... 肯定不是质数
            for (int i = x; i < n; i += x) {
                notPrimes[i] = true;
            }
        }
        return ans;

    }
   
}

415. 字符串相加(加法模板)

class Solution {
    public String addStrings(String num1, String num2) {
        /**
        分析:
        这个题干提示的很明显了,使用加法模板!
         */
         int len1 = num1.length() - 1, len2 = num2.length() - 1;
         // 使用sb进行动态修改
         StringBuilder sb = new StringBuilder();
         // 定义进位
         int carry = 0;
         while( len1 >= 0 || len2 >= 0){
             // 定义分位
             int x = len1 < 0 ? 0 : num1.charAt(len1) - '0';
             int y = len2 < 0 ? 0 : num2.charAt(len2) - '0';
             int sum = x + y + carry;
             sb.append(sum % 10);
             carry = sum / 10;

             len1--;
             len2--;
         }
         // 判断最后一个进位
         if(carry != 0){
             sb.append(carry);
         }
         return sb.reverse().toString();

    }
}

989. 数组形式的整数加法(加法模板)

class Solution {
    public List<Integer> addToArrayForm(int[] num, int k) {
        /**
        分析:
        本题是我使用加法模板的启蒙题~~~
         */
         int len = num.length - 1;
         // 定义结果
         LinkedList<Integer> res = new LinkedList<>();
         // 定义进位
         int carry = 0;
         while( len >= 0 || k != 0){
             // 定义分位
             int x = len >= 0 ? num[len] : 0;
             int y = k != 0 ? k % 10 : 0;
             int sum = x + y + carry;
             // 添加结果
             res.addFirst(sum % 10);
             carry = sum / 10;

             len--;
             k /= 10;
         }
         if(carry != 0){
             res.addFirst(carry);
         }
         return res;

    }
}

1232. 缀点成线(边界条件,分母的考虑)

在这里插入图片描述

class Solution {
    public boolean checkStraightLine(int[][] coordinates) {
        /**
        分析:
        依次判断相邻两点的斜率是否一致,这里如果直接使用斜率公式,有可能分母为0,所以需要变换为乘法!
        这里规定第一个点为起点,后面的计算都以起点为依据
         */
         // 定义起点
         int x0 = coordinates[0][0], y0 = coordinates[0][1];
         int deltaY = coordinates[1][1] - y0;
         int deltaX = coordinates[1][0] - x0;
         for(int i = 2; i < coordinates.length; i++){
             int deltaYi = coordinates[i][1] - y0;
             int deltaXi = coordinates[i][0] - x0;

             if(deltaY * deltaXi != deltaYi * deltaX){
                 return false;
             }
         }
         return true;    
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值