剑指 Offer 65. 不用加减乘除做加法
题目:写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。
示例:
输入: a = 1, b = 1
输出: 2
提示:
1、a, b 均可能是负数或 0
2、结果不会溢出 32 位整数
解题思路:
本题考察对位运算的灵活使用,即使用位运算实现加法。
设两数字的二进制形式 a, b ,其求和 s = a + b ,a(i) 代表 a 的二进制第 i 位,则分为以下四种情况:
a(i) | b(i) | 无进位和 n(i) | 进位 c(i+1) |
---|---|---|---|
0 | 0 | 0 | 0 |
0 | 1 | 1 | 0 |
1 | 0 | 1 | 0 |
1 | 1 | 0 | 1 |
观察发现,无进位和 与 异或运算 规律相同,进位 和 与运算 规律相同(并需左移一位)。因此,无进位和 n 与进位 c 的计算公式如下;
n=a⊕b 非进位和:异或运算
c=a&b<<1 进位:与运算+左移一位
(和s)=(非进位和n)+(进位c)。即可将s=a+b转化为:
s=a+b⇒s=n+c
循环求 n和 c,直至进位 c = 0;此时 s = n,返回 n 即可。
Q : 若数字 a 和 b 中有负数,则变成了减法,如何处理?
A : 在计算机系统中,数值一律用 补码 来表示和存储。补码的优势: 加法、减法可以统一处理(CPU只有加法器)。因此,以上方法 同时适用于正数和负数的加法 。
复杂度分析:
- 时间复杂度 O(1) : 最差情况下(例如 a= 0x7fffffff , b=1 时),需循环 32 次,使用 O(1) 时间;每轮中的常数次位操作使用 O(1) 时间。
- 空间复杂度 O(1): 使用常数大小的额外空间。
代码:
class Method{
public int add(int a, int b) {
while(b != 0) { // 当进位为 0 时跳出
int c = (a & b) << 1; // c = 进位
a ^= b; // a = 非进位和
b = c; // b = 进位
}
return a;
}
}
剑指 Offer 14- I. 剪绳子
题目:给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m-1] 。请问 k[0]k[1]…k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1
示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
提示:
2 <= n <= 58
解题思路:
以下数学推导总体分为两步:① 当所有绳段长度相等时,乘积最大。② 最优的绳段长度为 3 。
数学推导:
推论一: 将绳子 以相等的长度等分为多段 ,得到的乘积最大。
推论二: 尽可能将绳子以长度 3 等分为多段时,乘积最大。
切分规则:
算法流程:
复杂度分析:
- 时间复杂度O(1) : 仅有求整、求余、次方运算。
- 求整和求余运算:资料提到不超过机器数的整数可以看作是O(1);
- 幂运算:查阅资料,提到浮点取幂为O(1)。
- 空间复杂度O(1): 变量 a 和 b 使用常数大小额外空间。
代码:
class Method{
public int cuttingRope(int n) {
if(n <= 3) return n - 1;
int a = n / 3, b = n % 3;
if(b == 0) return (int)Math.pow(3, a);
if(b == 1) return (int)Math.pow(3, a - 1) * 4;
return (int)Math.pow(3, a) * 2;
}
}
贪心思路:
设一绳子长度为 n( n>1),则其必可被切分为两段 n=n1+n2。
根据经验推测,切分的两数字乘积往往原数字更大,即往往有n1×n2>n1+n2=n 。
- 例如绳子长度为 6 :6=3+3<3×3=9 ;
- 也有少数反例,例如 2 :2=1+1>1×1=1 。
- 推论一: 合理的切分方案可以带来更大的乘积。
设一绳子长度为n( n>1),切分为两段n=n1+n2,切分为三段n=n1+n2+n3。
根据经验推测,三段 的乘积往往更大,即往往有n1n2n3>n1n2。
- 例如绳子长度为9 :两段 9=4+5 和 三段 9=3+3+3,则有4×5<3×3×3 。
- 也有少数反例,例如6 :两段 6=3+3 和 三段 6=2+2+2,则有3×3>2×2×2。
- 推论二: 若切分方案合理,绳子段切分的越多,乘积越大。
总体上看,貌似长绳子切分为越多段乘积越大,但其实到某个长度分界点后,乘积到达最大值,就不应再切分了。
问题转化: 是否有优先级最高的长度x存在?若有,则应该尽可能把绳子以x长度切为多段,以获取最大乘积。
- 推论三: 为使乘积最大,只有长度为 2 和 3 的绳子不应再切分,且 3 比 2 更优 (详情见下表)。
总结:
今天抽时间回了一趟学校拿了我人生当中统招大专学历的倒数第二个荣誉证书!这个荣誉是“三好学生”。有些同学羡慕,可我并不觉得有什么可羡慕的!不过就是在荣誉奖项那一栏多占一行而已!对应届生来说其实社会上还是比较看重学历而已!接着就是工作经验和项目经验!其他行业也都类似!说白了就是工作能力,能否给企业或公司带来效益!如果能力不行,文凭再高,证书再多也不过是一堆过期的荣誉而已!
学校的样貌还是没有太大的改变!最让我忘不了的是学校的图书馆!可能我到图书馆的时间恰巧是中午,图书馆的老师应该都在午休!也不好去打扰老师午休!于是就去二楼看了一本关于SpringBoot和Spring框架的书,用了一个小时的时间,将这本书从头到尾的预览了一遍,当然自己清楚的知识速过,比较模糊的知识细看,突然发现用心读书的感觉真好!可惜以后再也没办法以一个学生的身份回图书馆看书了!但愿以后有时间再回学校看书吧!
希望各位在校的小伙伴们一定要利用好学校图书馆的这个宝库!它真的能给你带来许多意想不到的收获!或许三、四年能让你的各个方面提升不少!也不要像我一样等到步入社会时才知道有多后悔!
最后,愿我们都能在各行各业中能够取得不同的成就,不负亲人、朋友、老师、长辈和国家的期望!能够用自身的所学知识为国家贡献出自己的一份力量!一起加油!
2021年5月18日夜