1.前言
本人只是一个普通学校的平凡不知名学生,学着软件工程专业目前大二,成绩不名列前茅。今日惊醒发现自己不能再咸鱼下去了,要多点学习一些关于编程的知识。在此情况下想着学习还得要多做笔记的,但毕竟自己是个学电脑的总不能手写笔记记录吧,花费时间和花费力气,重新回头复习难找的等等问题都太麻烦了。最后打算在CSDN这发表博客记录一下自己的学习笔记也当是让自己学习自律一下,同时也能分享给他人,虽然没有各大佬那样文章教学的好但起码也能帮助到诸位一点点。该文章会根据本人的学习情况进行更新,学到什么感觉有用的都会往这上面进行记录。
本文章收录的内容大部分参考至网上各平台大佬博主的文章,同时也会经过自己的修改再发布,每处参考部分本人都会表明作者和原处链接。本人只为记录和分享下自己的学习经历和记录学习笔记,不作任何盈利行为。
本文章将分为三个种类型题目进行分类,分别是简单、中等、困难。
2.参考文章的作者和原文链接:
参考作者【墨鳌】原文链接:
面试题 08.05. 递归乘法 - 力扣(Leetcode)
参考作者 克利斯提亚诺-梅西 原文链接:
(3条消息) 【力扣面试】面试题 08.05. 递归乘法_克利斯提亚诺-梅西的博客-CSDN博客
3.简单
3-1.剑指 Offer 57 - II. 和为s的连续正数序列
输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
示例 1:
输入:target = 9
输出:[[2,3,4],[4,5]]
示例 2:
输入:target = 15
输出:[[1,2,3,4,5],[4,5,6],[7,8]]
限制:
1 <= target <= 10^5
代码:
class Solution {
public:
vector<vector<int>> findContinuousSequence(int target) {
vector<vector<int>> vec;//用vector容器创造一个储存数组(res)的数组
vector<int> res;//用vecetor容器创造一个数组res
int lo = 1;//lo指向res数组的第一个元素,初始时候
int hi = 2;//hi指向res数组的第二个元素,初始时候
while(hi<target){//while循环结束条件是hi指向target的时候
int curSum = (lo + hi) * (hi - lo + 1) / 2;//curSum是等差数列 的总和
if(curSum > target){//当总和大于target时lo向前一位
lo += 1;
}
if(curSum < target){//当总和小于target时hi向前一位
hi += 1;
}
if(curSum == target){//当总和等于target时
res.clear();//res数组清空
for(int k = lo;k <= hi;k++){//进入for循环k初始位置是lo结 束位置是大于hi时
res.emplace_back(k);//向res数组塞入(lo,hi)位置的数据
}
vec.emplace_back(res);//再把res数组的数据塞入vec数组
lo += 1;//然后lo自增,进行下一个循环
}
}
return vec;//直到while循环结束条件是hi指向target的时候返回vec数组
}
};
3-2.面试题 17.01. 不用加号的加法
设计一个函数把两个数字相加。不得使用+ 或者其他算术运算符。
示例:
输入: a =1, b = 1
输出: 2
提示:
a, b 均可能是负数或 0
结果不会溢出 32 位整数
1- class Solution {
2- public:
3- vector<vector<int>> findContinuousSequence(int target) {
4- vector<vector<int>> vec;//1- 用vector容器创造一个储存数组(res)的数组
5- vector<int> res;//用vecetor容器创造一个数组res
6- int lo = 1;//lo指向res数组的第一个元素,初始时候
7- int hi = 2;//hi指向res数组的第二个元素,初始时候
8- while(hi<target){//while循环结束条件是hi指向target的时候
9- int curSum = (lo + hi) * (hi - lo + 1) / 2;//curSum是等差数 列的总和
10- if(curSum > target){//当总和大于target时lo向前一位
11- lo += 1;
12- }
13- if(curSum < target){//当总和小于target时hi向前一位
14- hi += 1;
15- }
16- if(curSum == target){//当总和等于target时
17- res.clear();//res数组清空
18- for(int k = lo;k <= hi;k++){//进入for循环k初始位置是lo结 束位置是大于hi时
19- res.emplace_back(k);//向res数组塞入(lo,hi)位置的数据
20- }
21- vec.emplace_back(res);//再把res数组的数据塞入vec数组
22- lo += 1;//然后lo自增,进行下一个循环
23- }
24- }
25- return vec;//直到while循环结束条件是hi指向target的时候返回vec数组
26- }
};
3-3.剑指 Offer 65. 不用加减乘除做加法
写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。
示例:
输入: a = 1, b = 1
输出: 2
提示:
a, b 均可能是负数或 0
结果不会溢出 32 位整数
1. int getSum(int a, int b){
2. while(b != 0){
3. unsigned int carry = (unsigned int)(a & b) << 1;
4. a = a ^ b;
5. b = carry;
6. }
7. return a;
}
4.中等
4-1. 29. 两数相除
给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和mod 运算符。
返回被除数 dividend 除以除数 divisor 得到的商。
整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) =8 以及 truncate(-2.7335) = -2
示例 1:
输入: dividend = 10, divisor = 3
输出: 3
解释: 10/3 = truncate(3.33333..) = truncate(3) = 3
示例 2:
输入: dividend = 7, divisor = -3
输出: -2
解释: 7/-3 = truncate(-2.33333..) = -2
提示:
被除数和除数均为32 位有符号整数。
除数不为 0。
假设我们的环境只能存储32 位有符号整数,其数值范围是[
,
]
。本题中,如果除法结果溢出,则返回
1- class Solution {
2- public:
3- vector<vector<int>> findContinuousSequence(int target) {
4- vector<vector<int>> vec;//用vector容器创造一个储存数组(res)的数组
5- vector<int> res;//用vecetor容器创造一个数组res
6- int lo = 1;//lo指向res数组的第一个元素,初始时候
7- int hi = 2;//hi指向res数组的第二个元素,初始时候
8- while(hi<target){//while循环结束条件是hi指向target的时候
9- int curSum = (lo + hi) * (hi - lo + 1) / 2;//curSum是等差数 列的总和
10- if(curSum > target){//当总和大于target时lo向前一位
11- lo += 1;
12- }
13- if(curSum < target){//当总和小于target时hi向前一位
14- hi += 1;
15- }
16- if(curSum == target){//当总和等于target时
17- res.clear();//res数组清空
18- for(int k = lo;k <= hi;k++){//进入for循环k初始位置是lo结 束位置是大于hi时
19- res.emplace_back(k);//向res数组塞入(lo,hi)位置的数据
20- }
21- vec.emplace_back(res);//再把res数组的数据塞入vec数组
22- lo += 1;//然后lo自增,进行下一个循环
23- }
24- }
25- return vec;//直到while循环结束条件是hi指向target的时候返回vec数组
26- }
27- };
4-2. 371. 两整数之和
给你两个整数 a 和 b ,不适用运算符 + 和 - ,计算并返回两整数之和。
示例 1:
输入:a = 1, b = 2
输出:3
示例 2:
输入:a = 2, b = 3
输出:5
提示:
-1000 <= a, b <= 1000
参考题目讲解:
思路和算法
虽然题目只要求了不能使用运算符 + 和 - ,但是原则上来说也不宜使用类似的运算符+= 和 -= 以及sum 等方法。于是,我们使用位运算来处理这个问题。
首先,考虑两个二进制位相加的四种情况如下:
异或
0 + 0 = 0
0 + 1 = 1
1 + 0 = 1
1 + 1 = 0 (进位)
可以发现,对于整数 a 和 b
在不考虑进位的情况下,其无进位加法结果为 a⊕b(异或)
而所有需要进位的位为 a &b,进位后的进位结果为(a & b)<< 1。
1. int getSum(int a, int b){
2. while(b != 0){
3. unsigned int carry = (unsigned int)(a & b) << 1;
4. a = a ^ b;
5. b = carry;
6. }
7. return a;
}
4-3.剑指 Offer 64. 求1+2+…+n
求 1+2+...+n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
示例 1:
输入: n = 3
输出: 6
示例 2:
输入: n = 9
输出: 45
限制:
1 <= n <= 10000
1. int sumNums(int n){
2. bool arr[n][n+1];
3. return sizeof(arr)>>1;
}
4-4.面试题 16.01. 交换数字
编写一个函数,不用临时变量,直接交换numbers = [a, b]中a与b的值。
示例:
输入: numbers = [1,2]
输出: [2,1]
提示:
numbers.length == 2
-2147483647 <= numbers[i] <= 2147483647
1- 方法一:
1. class Solution {
2. public:
3. vector<int> swapNumbers(vector<int>& numbers) {
4. numbers[0]^=numbers[1];
5. numbers[1]^=numbers[0];
6. numbers[0]^=numbers[1];
7. return numbers;
8. }
};
引入异或运算
0^0 0
1^1 0
0^1 1
1^0 1
也就是对于 0 和 1,相同的数异或为 0,不同的数异或为 1。
这样就有了三个比较清晰的性质:
两个相同的十进制数异或的结果一定位零。
任何一个数和 0 的异或结果一定是它本身。
异或运算满足结合律和交换律。
我们直接来看(1) 和 (2) 这两句话,相当于b等于a ^ b ^ b,根据异或的几个性质,我们知道,这时候的b的值已经变成原先a的值了。
而再来看最后一句话,相当于a等于a ^ b ^ a,还是根据异或的几个性质,这时候,a的值已经变成了原先b的值。
从而实现了变量a和b的交换。
1- 方法二:
class Solution {
public:
vector<int> swapNumbers(vector<int>& numbers) {
numbers[0] = numbers[0] + numbers[1];
numbers[1] = numbers[0] - numbers[1];
numbers[0] = numbers[0] - numbers[1];
return numbers;
}
};
缺点比如说int整型数据的话有可能会相加溢出
4-5.面试题 08.05. 递归乘法
递归乘法。 写一个递归函数,不使用 * 运算符, 实现两个正整数的相乘。可以使用加号、减号、位移,但要吝啬一些。
示例1:
输入:A = 1, B = 10 输出:10
示例2:
输入:A = 3, B = 4 输出:12
提示:
保证乘法范围不会溢出
方法一:运用二维数组,求数组的长度空间。
class Solution {
public:
int multiply(int A, int B) {
bool a[A][B];
return (int)sizeof(a);
}
};
方法二:通过位运算递归,加A次B。
int multiply(int A, int B){
if(A>B){//将A的值和B的值交换
A = A ^ B;
B = A ^ B;
A = A ^ B;
}
if(A>0){//判断A大于0进入
return B + multiply(A-1,B);//递归一次A的值减一次,B的值加一次B
}
return 0;
}
4-6. 29. 两数相除
给你两个整数,被除数 dividend 和除数 divisor。将两数相除,要求 不使用 乘法、除法和取余运算。
整数除法应该向零截断,也就是截去(truncate)其小数部分。例如,8.345 将被截断为 8 ,-2.7335 将被截断至 -2 。
返回被除数 dividend 除以除数 divisor 得到的 商 。
注意:假设我们的环境只能存储 32 位 有符号整数,其数值范围是 [
,
− 1] 。本题中,如果商 严格大于
− 1 ,则返回
− 1 ;如果商 严格小于
,则返回
。
示例 1:
输入: dividend = 10, divisor = 3 输出: 3 解释: 10/3 = 3.33333.. ,向零截断后得到 3 。
示例 2:
输入: dividend = 7, divisor = -3 输出: -2 解释: 7/-3 = -2.33333.. ,向零截断后得到 -2 。
提示:
<= dividend, divisor <=
- 1
divisor != 0
class Solution {
public:
int divide(int dividend, int divisor) {
}
};
5.困难