当前位置: 首页 > news >正文

LeetCode刷题——29. Divide Two Integers(Part 1靠自己)

当我第一次看到这个题目时候我我心想不就是两数相除嘛,这么简单的题目为什么要放到 Medium 中,事实证明我当时的想法Too young,Too simple,Too naive 以至于被打脸n次,可以直接查看最后答案,中间我的思路自白可以忽略。

clipboard.png

题目大意

给两个数字,除数和被除数,在不使用乘、除、取模的方法做除法,返回两数之商

备注:
1.除数和被除数都是32位有符号整数
2.除数不为0
3.假设我们正在处理一个只能在32位有符号整数范围内存储整数的环境[−231,  231 − 1],对于这个问题如果结果溢出了,则可以返回231 − 1

解题代码

public class Solution {
    /**整体思路是用减法**/
    public int divide(int dividend, int divisor) {
        // 符号相同用减法
        if(dividend==Integer.MIN_VALUE&&divisor==-1) {
            return Integer.MAX_VALUE;
        }
        
        if ((dividend ^ divisor) >= 0) {
            return getQuotientUsesSubtraction(dividend, divisor);
        } else {
            int absDividend = Math.abs(dividend);
            int absDivisor = Math.abs(divisor);
            if (absDividend < 0) {
                absDivisor = -absDivisor;
            } else if (absDivisor < 0) {
                absDividend = -absDividend;
            }
            return 0 - getQuotientUsesSubtraction(absDividend, absDivisor);
        }
    }

    /**
     * 使用减法获取两个数的商 除数dividend,被除数divisor
     * 条件:dividend*divisor >0 且divisor>0
     */
    private int getQuotientUsesSubtraction(int dividend, int divisor) {
        int quotient = 0;
        if (dividend >= 0)
            while (dividend >= divisor) {
                quotient++;
                dividend = dividend - divisor;
            }
        else {
            while (dividend <= divisor) {
                quotient++;
                dividend = dividend - divisor;
            }
        }
        return quotient;

    }
}

测试用例

用的是 junit5,如果是4或者3的胖友自己修改下

import org.junit.Assert;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

@DisplayName("不用乘除取模运算计算除数")
public class TestSolution {
    @Test
    @DisplayName("MIN_VALUE情况和1")
    void e1() {
        int out = Integer.MIN_VALUE;
        Solution s = new Solution();
        Assert.assertEquals(out, s.divide(Integer.MIN_VALUE, 1));
    }
    @Test
    @DisplayName("MIN_VALUE情况和-1")
    void e9() {
        int out = Integer.MAX_VALUE;
        Solution s = new Solution();
        Assert.assertEquals(out, s.divide(Integer.MIN_VALUE, -1));
    }

    @Test
    @DisplayName("除数是0情况")
    void e2() {
        int out = 0;
        Solution s = new Solution();
        Assert.assertEquals(out, s.divide(0, 1));
    }

    @Test
    @DisplayName("符号相反")
    void e3() {
        int out = -1;
        Solution s = new Solution();
        Assert.assertEquals(out, s.divide(1, -1));
    }

    @Test
    @DisplayName("符号相同")
    void e4() {
        int out = 1;
        Solution s = new Solution();
        Assert.assertEquals(out, s.divide(-1, -1));
    }

    @Test
    @DisplayName("除数MIN_VALUE和被除数MAX_VALUE")
    void e5() {
        int out = -1;
        Solution s = new Solution();
        Assert.assertEquals(out, s.divide(Integer.MIN_VALUE, Integer.MAX_VALUE));
    }

    @Test
    @DisplayName("除数MAX_VALUE和被除数MIN_VALUE")
    void e6() {
        int out = 0;
        Solution s = new Solution();
        Assert.assertEquals(out, s.divide(Integer.MAX_VALUE, Integer.MIN_VALUE));
    }

    @Test
    @DisplayName("冒烟测试10,3")
    void e7() {
        int out = 3;
        Solution s = new Solution();
        Assert.assertEquals(out, s.divide(10, 3));
    }

    @Test
    @DisplayName("冒烟测试7,-3")
    void e8() {
        int out = -2;
        Solution s = new Solution();
        Assert.assertEquals(out, s.divide(7, -3));
    }

}

时间和空间复杂度

clipboard.png

clipboard.png

看到上面的运行时间心里凉了大半啊!,看来还有更好的方法,有时间的话写一下最优解的思路
,此处立下flag,我要写 Part 2靠大家


初级解题思路(?‍♀️此处开始为我折腾过程不重要,可以忽略)

既然乘、除、取模都用不了就用减法吧。两数取商用减法的角度思考?就是,被除数可以减几个除数。因为题目取值范围是包含负值的所以要区分符号,相同符号则返回正数,符号相反则返回负值

第一次尝试(失败?)

  • 思路:
  1. 取两个数的绝对值
  2. 当被除数大于除数时,计算相减次数,小于时则直接返回0
  3. 当两数相同符号则返回相减次数,符号相反则返回相减次数负值
  • 代码:

    class Solution {
        public int divide(int dividend, int divisor) {
            int absDividend= Math.abs(dividend);
            int absDivisor= Math.abs(divisor);
            int quotient =0;
            while(absDividend>absDivisor){
                quotient++;
                absDividend=absDividend-absDivisor;
            }
            if((dividend^divisor)>= 0){
                return quotient;
            }else{
                return 0-quotient;
            }
        }
    }
  • 结果
    自测的两个冒烟测试用例通过,但是用例[1,1]没用通过

第二次尝试(失败?)

  • 分析失败原因
    循环的时候没有考虑相等的情况
  • 修改方式
    while(absDividend>absDivisor)改为while(absDividend>=absDivisor)
  • 修改后[1,1]用例通过,但是未通过用例[-2147483648,-1]

第三次尝试(失败?)

  • 分析失败原因
    没有考虑负数的最大值的绝对值溢出了
  • 修改方式
    修改思路
    1.符号相同的时候直接获取相减次数
    2.符号不同的时候,取两数的绝对值
    3.判断两数的绝对值是否大于0,(小于0的情况是取值为−231
    4.大于0时,返回相减次数的绝对值
    5.小于0时,将大于0的数取反数再计算相减次数,返回相减次数的反数
  • 代码

    class Solution {
        public int divide(int dividend, int divisor) {
            // 符号相同用减法
            if ((dividend ^ divisor) >= 0) {
                return getQuotientUsesSubtraction(dividend, divisor);
            } else {
                int absDividend = Math.abs(dividend);
                int absDivisor = Math.abs(divisor);
                if (absDividend < 0) {
                    absDivisor = -absDivisor;
                } else if (absDivisor < 0) {
                    absDividend = -absDividend;
                }
                return 0 - getQuotientUsesSubtraction(absDividend, absDivisor);
            }
        }
       
        private int getQuotientUsesSubtraction(int dividend, int divisor) {
            int quotient = 0;
            if (dividend >= 0)
                while (dividend >= divisor) {
                    quotient++;
                    dividend = dividend - divisor;
                }
            else {
                while (dividend <= divisor) {
                    quotient++;
                    dividend = dividend - divisor;
                }
            }
            return quotient;
    
        }
    }
  • 结果
    未通过用例[-2147483648,-1],但是可以处理除数或被除数为-2147483648的其他用例可以处理

第四次尝试(成功✌️)

  • 分析失败原因
    没有考虑负数最大值除以-1导致溢出
  • 修改方式
    直接将这个用例视为特殊情况处理之,直接返回整值最大

相关文章:

  • 程序猿福利来啦,神目AI开放平台免费送人脸识别SDK啦
  • java异常
  • Go test 命令行参数
  • 观察者模式与发布/订阅模式学习
  • go标准库的学习-runtime
  • java多线程
  • 喜讯:以太坊“君士坦丁堡”升级,截止目前稳定运转
  • 如何找到 Kafka 集群的吞吐量极限?
  • Atcoder:AGC004F Namori
  • 如何学习JavaEE,项目又该如何做?
  • Spring Cloud构建微服务架构—服务消费(Ribbon)
  • long a = 136;
  • 使用权重正则化较少模型过拟合
  • Angular 响应式表单之下拉框
  • 基于 Babel 的 npm 包最小化设置
  • JS 中的深拷贝与浅拷贝
  • 《Java编程思想》读书笔记-对象导论
  • MySQL的数据类型
  • October CMS - 快速入门 9 Images And Galleries
  • Redis的resp协议
  • Spring Boot快速入门(一):Hello Spring Boot
  • SQLServer之创建显式事务
  • vue-cli3搭建项目
  • Web设计流程优化:网页效果图设计新思路
  • 湖南卫视:中国白领因网络偷菜成当代最寂寞的人?
  • 如何合理的规划jvm性能调优
  • 山寨一个 Promise
  • 微信小程序填坑清单
  • 为视图添加丝滑的水波纹
  • 【干货分享】dos命令大全
  • 阿里云服务器如何修改远程端口?
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • ​2021半年盘点,不想你错过的重磅新书
  • #设计模式#4.6 Flyweight(享元) 对象结构型模式
  • (3)Dubbo启动时qos-server can not bind localhost22222错误解决
  • (3)选择元素——(17)练习(Exercises)
  • (30)数组元素和与数字和的绝对差
  • (4)事件处理——(7)简单事件(Simple events)
  • (6)添加vue-cookie
  • (初研) Sentence-embedding fine-tune notebook
  • (附源码)springboot家庭财务分析系统 毕业设计641323
  • (黑马出品_高级篇_01)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式
  • (三)模仿学习-Action数据的模仿
  • (转)Android中使用ormlite实现持久化(一)--HelloOrmLite
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • [Android]竖直滑动选择器WheelView的实现
  • [bzoj1324]Exca王者之剑_最小割
  • [CareerCup] 17.8 Contiguous Sequence with Largest Sum 连续子序列之和最大
  • [github配置] 远程访问仓库以及问题解决
  • [IOI2007 D1T1]Miners 矿工配餐
  • [iphone-cocos2d]关于Loading的若干处理和讨论
  • [Java][算法 双指针]Day 02---LeetCode 热题 100---04~07
  • [LeetCode]Reverse Linked List II
  • [loj#115] 无源汇有上下界可行流 网络流