JAVA 两数求商

题目描述:

给定两个整数 a 和 b ,求它们的除法的商 a/b ,要求不得使用乘号 ‘*’、除号 ‘/’ 以及求余符号 ‘%’ 。
注意:
整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−2 的31次方, 2 的31方 −1 ]。本题中,如果除法结果溢出,则返回 2^31 − 1
示例 1:

输入:a = 15, b = 2
输出:7
解释:15/2 = truncate(7.5) = 7
示例 2:

输入:a = 7, b = -3
输出:-2
解释:7/-3 = truncate(-2.33333…) = -2
示例 3:

输入:a = 0, b = 1
输出:0
示例 4:

输入:a = 1, b = 1
输出:1
提示:

-2 ^ 31 <= a, b <= 2^31 - 1
b != 0

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/xoh6Oh

代码与分析:

package cn.edu.chong;

public class SmallTest {
    public static void main(String[] args) {
        SmallTest re = new SmallTest();
        int r = re.Sum(15,2);
        System.out.println(r);
    }
    public  int Sum( int a , int b){

        if(a == 0) return 0; //被除数为0直接结束
        if( a == Integer.MIN_VALUE && b == -1)  //防止超出边界,具体解释在下面
            return Integer.MAX_VALUE;

        int sign = (a  > 0 )  ^ ( b > 0) ? -1 : 1; //与或  可以简化代码
    //    System.out.println(sign);
        /*
        32位最大值:2^31-1 = 2147483647
        32位最小值:-2^31 = -2147483648
        1.综合上述:当 a 是最值 b 是 -1 时,此时结果会超出Int 的范
        2.a 取最小值,又取绝对值时,还是它自己本身(解决方式 a 与 b 转换数据类型long 类型进行解决)
        3.由于Math.abs的目的是将复数转成正数,所以咱们直接将正数转成复数进行计算,这样做的目的就是消除long类型
        (因为本体要求数据类型不能超过32位)
          a  = Math.abs(a);----> a = -a;
        b = Math.abs(b);--------> b = -b;
        以上的方式导致时间复杂度过高,程序运行会很慢,解决方式就是:
        我们每次减去b倍数时,就能解决上上面超时的问题
        此时代码主要需要改动的地方就在while循环里面

         */
//        a  = Math.abs(a);
//        b = Math.abs(b);

      if (a > 0) a = -a;
      if (b > 0) b = -b;
        //System.out.println(a);
        int res = 0;
        while( a <= b){            // 取小于符号 : 是因为我们取的是负数
            int va = b;
            int k = 1;
            while (va >= 0xc0000000 && a <= va + va){  //这里防止va越界,应加上一个判断:va > 0xc0000000 = -2^31 的一半
                va += va;           //除数加除数 就是取b的整数倍
                k += k;
            }

            a -= va;
            res += k;
        }
        return sign == 1 ? res : -res;

        /*
        但会出现都时间上会出问题:
        我们可以使用位移运算来进行计算更方便一些
        不过此时我们需要将while 循环进行进一步的优化
        进行说明:
        在此之前我们需要得到a 与 b 的数值为正的,所以我们又一次利用 Math.abs();
        我们可以从b最大的整数倍31进行去运算,提高了代码的运算效率
        a >>> i 这是我们将防止我们得到的是 最小的-2147483648 这个数,因为此时就算我们取绝对值,取出来的也是最小的负数
        所以我们利用无符号位移解决此问题
         (a >>> i) - b >= 0 这是我们也是为了防止俩数都有可能取到负数时,导致for为死循环

        for ( int i = 31; i >= 0; i ++){
        if( (a >>> i) -b >=0){
        a -= b;
        res +=(1 << i);
        }
        }
         */
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这是一个java实现链表相加的代码: ``` /** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { ListNode dummy = new ListNode(0); ListNode current = dummy; int carry = 0; while (l1 != null || l2 != null) { int x = l1 == null ? 0 : l1.val; int y = l2 == null ? 0 : l2.val; int sum = carry + x + y; carry = sum / 10; current.next = new ListNode(sum % 10); current = current.next; if (l1 != null) { l1 = l1.next; } if (l2 != null) { l2 = l2.next; } } if (carry > 0) { current.next = new ListNode(carry); } return dummy.next; } } ``` 具体解释: - 定义一个ListNode类表示链表的每一个节点,包含val和next两个属性。 - 定义一个Solution类,其中包含一个方法addTwoNumbers,该方法接收两个链表作为输入,返回一个表示和的链表。 - 在方法中,定义dummy节点,并用current指针指向dummy。dummy节点是一个虚拟的节点,用于储存结果链表的第一个节点。 - 定义一个变量carry来储存进位的数值。 - 通过while循环,遍历l1和l2两个链表,并将其中的数值加起来。 - 如果有进位,就在最后加上一个carry节点。 - 返回dummy.next,以跳过虚拟节点dummy,从而返 ### 回答2: 请注意,由于每个节点只能存储一位数字,并且数字是按逆序的方式存储的,因此在计算过程中需要注意进位的处理。 以下是使用Java代码实现的解答,对每行代码进行了详细解释: ```java public ListNode addTwoNumbers(ListNode l1, ListNode l2) { ListNode dummyHead = new ListNode(0); // 创建一个虚拟头节点,方便构建链表 ListNode p = l1, q = l2, curr = dummyHead; // 分别指向两个链表和结果链表的当前位置 int carry = 0; // 初始进位为0 while (p != null || q != null) { // 遍历两个链表的每一位数字 int x = (p != null) ? p.val : 0; // 如果p不为空取p的值,否则为0 int y = (q != null) ? q.val : 0; // 如果q不为空取q的值,否则为0 int sum = carry + x + y; // 两个节点和进位相加得到的值 carry = sum / 10; // 新的进位 curr.next = new ListNode(sum % 10); // 创建新的节点,存储当前位计算结果的个位数 curr = curr.next; // 结果链表指针向后移动 if (p != null) p = p.next; // 遍历完p链表后p指针后移 if (q != null) q = q.next; // 遍历完q链表后q指针后移 } if (carry > 0) { // 如果最高位有进位,则创建新的节点保存进位值 curr.next = new ListNode(carry); } return dummyHead.next; // 返回结果链表(去掉虚拟头节点) } ``` 这段代码通过迭代两个链表的每一位数字,并将它们相加,同时处理进位。创建一个虚拟头节点,便于构建结果链表。遍历过程中,分别取出两个链表当前位置的值,加上前一位的进位值,得到一个新的sum值。同时更新进位值carry,并创建一个新节点存储sum值的个位数,将该节点链接到结果链表中。同时移动各个链表的指针,继续下一位的计算,直到两个链表的数字都遍历完。 最后,如果最高位有进位,则再创建一个新节点保存进位值。最后返回结果链表即可。 ### 回答3: 请参考以下代码实现: ```java public class Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { ListNode dummyHead = new ListNode(0); // 创建一个虚拟头节点 ListNode curr = dummyHead; // 使用curr指针遍历链表,初始指向头节点 int carry = 0; // 进位值,初始为0 while (l1 != null || l2 != null) { // 当l1或l2还有节点时,继续遍历 int x = (l1 != null) ? l1.val : 0; // 如果l1还有节点,取节点值,否则为0 int y = (l2 != null) ? l2.val : 0; // 如果l2还有节点,取节点值,否则为0 int sum = carry + x + y; // 两个节点值及进位值的和 carry = sum / 10; // 更新进位值 curr.next = new ListNode(sum % 10); // 创建新节点,值为相加结果的个位数 curr = curr.next; // 当前节点指针后移 if (l1 != null) l1 = l1.next; // l1指针后移 if (l2 != null) l2 = l2.next; // l2指针后移 } if (carry > 0) { // 遍历结束后,如果进位值大于0,则需要额外创建一个节点 curr.next = new ListNode(carry); } return dummyHead.next; // 返回虚拟头节点的下一个节点,即为链表的头节点 } } ``` 解释: 1. 创建一个虚拟头节点dummyHead,用于返回相加后的链表的头节点。 2. 创建一个指针curr,用于遍历新链表,初始指向dummyHead。 3. 定义进位值carry,初始为0。 4. 使用while循环遍历两个链表,当l1或l2还有节点时,继续遍历。 5. 获取l1和l2当前节点的值,如果当前节点为空,则取0。 6. 计算两个节点值及进位值的和,将其除以10的商作为新的进位值。 7. 创建一个新的节点,节点值为相加结果的个位数。 8. 将当前节点的next指向新节点,当前节点指针后移。 9. 如果l1或l2还有节点,则将对应的指针后移。 10. 遍历结束后,如果进位值大于0,则需要额外创建一个节点,节点值为进位值。 11. 返回虚拟头节点的下一个节点,即为相加后链表的头节点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值