刷穿剑指offer-Day01-整数I

简介: 刷穿剑指offer-Day01-整数I

前序


这是刷穿剑指offer系列的第一篇文章,在这里需要简单和大家说明下关于这个系列的一些说明。


数据结构学习顺序

如果大家购买了剑指offer-专项突破,那么大家肯定看到了关于这本书目录对应的数据结构。但前文也说了,这本书的价值更多的在于题目上,如果知道了题目,那么就没有太大的必要去买这本书了,那么怎么获取本书的目录与所有题目呢?这里和大家介绍下。

  1. 首先打开力扣首页并进入题库专栏

网络异常,图片无法展示
|

  1. 选择剑指offer专项突击版,即可获取到本书大纲与所有题目列表。

网络异常,图片无法展示
|


关于文章和解题

昨天的公众号文章介绍了咱们的刷题学习策略,再这里简单复述下:

  1. 每种数据结构、每道解题,都会讲解Python、Java对应的知识内容。
  2. 针对每种数据结构,大概会花 4 天的时间进行学习。
  3. 第一天介绍这个数据结构对应的Python、Java语言涉及到的知识点,然后给出一道简单题目完成入门。
  4. 之后的两天,每天会讲解本书中的两道题目,并在讲解题目的同时,针对这道题涉及到的知识点进行总结
  5. 最后一天,针对该数据结构以及这三天的题目,进行一个总结,并推荐力扣上同类型题目列表,供大家深入学习与验证这种数据结构的学习成果。

具体每天文章的更新时间,现在还不能确定,因为没有存稿,都是每天学习、总结后写文章,所以想固定一个时间比较难。更新时会在刷穿剑指offer的微信群通知大家,针对文章或者当天的题目有什么问题也欢迎大家在群里相互讨论。

如果现在还没有加入群的朋友,可以通过公众号、微信联系我,但为了避免打广告的马甲号,入群前请向我提供你的力扣用户名、个人主页链接、或者力扣个人二维码。我会关注你确认身份后,拉你入群。

好了,要说明的就这些内容了,让我们开始今天的算法学习之旅吧!


Day01-整数I


本以为二进制的考题很少,毕竟有些偏底层,但最近不管周赛还是群友提问,二进制的题目如雨后春笋的都冒出来了,所以借着本章的机会好好复习下这方面的知识吧。

对于Python玩家来说,数字只分两种:整型、浮点型,不是小数的都是整数真简单啊!但这里有一个Python的面试考点:复数(大家仅做了解即可。)

复数(Complex)是Python的内置类型,直接书写即可,复数由实部(real)和虚部(imag)构成,在 Python 中,复数的虚部以j或者J作为后缀,具体格式为: a + bj a 表示实部,b 表示虚部。

然而,对于Java来说,单说整数就细分为了byte、short、int、long。

这里简单总结下Java的整数类型:

数据类型 范围(^ 代表次方) 字节数
byte 类型 -128(-2 ^ 7) ~ 127(2 ^ 7 - 1) 1字节,8位
short 类型 -32768(-2 ^ 15)~ 32767(2 ^ 15 - 1) 2字节,16位
int 类型 -2,147,483,648(-2 ^ 31)~ 2,147,483,647(2 ^ 31 - 1) 4字节,32位
long 类型 -2 ^ 63 ~ 2 ^ 63 -1 (数值太长没必要记了...) 8字节,64位

那么,在做整数题目时,Python与Java的差别是什么呢?

  • Python: 放心大胆无脑冲!
  • Java:在越界的边缘战战兢兢...


二进制转换


在讲解二进制的与、或、异或方法前,首先需要复习下Java和Python十进制和二进制的互转的api操作。

转换方式 语言 api(函数) 结果
十进制转二进制 Java Integer.toBinaryString(int: 100) "1100100"
十进制转二进制 Python bin(100) "0b1100100"
二进制转十进制 Java Integer.valueOf(s: "1100100",radix: 2) 100
二进制转十进制 Python int('0b1100100',2) 100

不管是Java还是Python在进行二进制转换后,得到的结果都是字符串,只是python会多一个"0b"的前缀。然而只有这么一点区别么?错了!

Java的二进制是存在符号位的,而Python是不存在符号位的,我们以-10举例:

Integer.toBinaryString(-10) -> "11111111111111111111111111110110"

bin(-10) -> "-0b101"

另外负数的二进制Python可以直接转化为十进制,但Java则不行…需要按位取反+1后再进行转化。

这里的语言差异需要大家留意!


与、或、异或


与、或、异或的运算都是将两个数字转化为二进制数后,按位比较的,运算规律Java与Python一致,具体如下图:

与 ( & ) 0 & 0 = 0 1 & 0 = 0 0 & 1 = 0 1 & 1 = 1
或( | ) 0 | 0 = 0 1 | 0 = 1 0 | 1 = 1 1 | 1 = 1
异或( ^ ) 0 ^ 0 = 0 1 ^ 0 = 1 0 ^ 1 = 1 1 ^ 1 = 0

与、或 操作符合日常逻辑,异或操作大家只要记住,相同为0 ,不同为1即可。

PS: Java 在遇到与或是经常会顺带问问短路与 ( && ) 短路或( || )的区别,即遇到前半部分符合条件立即终止判断。


位移操作


位运算分 左位移、右位移,符号对应<< 和 >>,简单来说就是将数字 m 向左、右移动n位。

如果是左移,最左边的n位将被丢弃,同时使用n个0进行补充至字符串末尾。

如果是右移,字符串末尾的n位被丢弃,但处理左边位时默认补0?No,针对Java等有符号位的语言,需要补充符号位,即正数补0,负数补1!

以上就是针对整数这章,初步涉及到的算法知识,后续会根据题目,再进一步补充,好了,开始做题吧!


剑指Offer001.整数除法


https://leetcode-cn.com/problems/xoh6Oh/

难度:简单


题目:


给定两个整数 a 和 b ,求它们的除法的商 a/b ,要求不得使用乘号 '*'、除号 '/' 以及求余符号 '%' 。

注意:

  • 整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2
  • 假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−2 ^ 31, 2 ^ 31−1]。本题中,如果除法结果溢出,则返回 2 ^ 31 − 1

提示:

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


示例:


示例 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


分析


首先这种不能使用xxx方法的题目,一般机试时是不会出的,因为限制不了编辑器,人工阅卷又需要耽误时间。

但正因为不会出现在机试中,所以在手撕算法时却会成为热门,所以请不要违背题意的直接使用乘、除提交题目。

拿示例一来说,一个最直观的方法就是循环使用a-b,计算减了多少次,即可得到结果。

但请注意a、b的取值范围,如果a为2 ^ 31−1,b为1那么仅一次就需要计算2 ^ 31−1次,所以这个思路是不可行的。

那么,既然不能从被除数上下手,能否通过除数进行操作呢?如果大家对二分搜索熟悉,相信很快能找到思路。

  1. 初始化返回值ret = 0
  2. 如果换成如果被除数大于除数,则除数扩大一倍
  3. 若被除数仍大于除数,这除数再次扩大一倍
  4. 直到除数下一次翻倍比被除数大时,将被除数减去除数,并将ret+=除数扩大的倍数,结束这一轮循环
  5. 重复2、3、4,直到被除数小于除数,终止循环并返回ret即可。

另外:在计算开始时,我们需要注意判断除数和被除数的正负号问题。如果是Python,只需要记录正负号即可。但对于Java而言,

由于负数的取值比正数大1,转换成正数计算会造成溢出,所以简单的方式是将数字转化为负数来进行比较。


解题:


class Solution:
    def divide(self, a: int, b: int) -> int:
        ret = 0
        flag = False if (a > 0 and b > 0) or (a < 0 and b < 0) else True
        a, b = abs(a), abs(b)
        def calc(x, y):
            n = 1
            while x > y << 1:
                y <<= 1
                n <<= 1
            return n, y
        while a >= b:
            cnt, val = calc(a, b)
            ret += cnt
            a -= val
        ret = -ret if flag else ret
        return ret - 1 if ret >= 2 ** 31 else ret

class Solution {
    public int divide(int a, int b) {
        int flag = 0;
        if (a > 0) {
            a = -a;
            flag += 1;
        }
        if (b > 0) {
            b = -b;
            flag += 1;
        }
        int ret = calc(a, b);
        if (flag != 1 && ret == Integer.MIN_VALUE) {
            ret++;
        }
        return flag == 1 ? ret : -ret;
    }
    private int calc(int a, int b) {
        int ret = 0;
        while (a <= b) {
            int cnt = 1;
            int val = b;
            while (val >= Integer.MIN_VALUE >> 1  && a <= val << 1) {
                cnt += cnt;
                val += val;
            }
            ret -= cnt;
            a -= val;
        }
        return ret;
    }
}




相关文章
|
存储 算法 Java
刷穿剑指offer-Day02-整数II
刷穿剑指offer-Day02-整数II
92 0
|
算法 Java 测试技术
刷穿剑指offer-Day03-整数III-快速幂
刷穿剑指offer-Day03-整数III-快速幂
125 0
|
存储 算法 Java
刷穿剑指offer-Day05-数组I
刷穿剑指offer-Day05-数组I
109 0
|
Java Python
刷穿剑指offer-Day06-数组II
刷穿剑指offer-Day06-数组II
117 0
|
算法 Java Python
刷穿剑指offer-Day08-字符串I 字符串知识总结与题型讲解
刷穿剑指offer-Day08-字符串I 字符串知识总结与题型讲解
111 0
|
存储 算法 Java
刷穿剑指offer-Day07-数组III 前缀和知识讲解!
刷穿剑指offer-Day07-数组III 前缀和知识讲解!
92 0
|
算法 Java Python
刷穿剑指offer-Day10-字符串III 回文串专题
刷穿剑指offer-Day10-字符串III 回文串专题
97 0
【刷穿 LeetCode】541. 反转字符串 II : 简单字符串模拟
【刷穿 LeetCode】541. 反转字符串 II : 简单字符串模拟
|
存储 算法
【刷穿 LeetCode】1. 两数之和(简单)
【刷穿 LeetCode】1. 两数之和(简单)
【每日算法/刷穿 LeetCode】992. K 个不同整数的子数组(困难)
【每日算法/刷穿 LeetCode】992. K 个不同整数的子数组(困难)