慢慢来,比较快。
尽量保证学过的都能复现,没弄懂的就多学几遍多敲几遍,总能成功的。
文章目录
一、移动零
题目
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
思路
双指针法
-
快指针所获取的值赋给慢指针所在的位置
快指针:寻找不等于 val 的数
慢指针:指向有效元素的下标 -
fast 指针必须一直动
-
fast所指元素 != val时:slow指针向前移,fast移
fast所指元素 == val时:slow指针不动,fast移
nums[slow++] = nums[fastI]; // 先将fast赋值给slow,slow再往后移一位
代码
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int slow = 0;
for(int fast = 0; fast < nums.size(); fast++){
if(nums[fast] != 0){
nums[slow++] = nums[fast];
}
}
while(slow < nums.size()){
nums[slow++] = 0;
}
}
};
二、杨辉三角
题目
给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。
在「杨辉三角」中,每个数是它左上方和右上方的数的和。
-
示例 1:
输入: numRows = 5
输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]] -
示例 2:
输入: numRows = 1
输出: [[1]]
思路
- 把杨辉三角的每一排左对齐:
[1]
[1,1]
[1,2,1]
[1,3,3,1]
[1,4,6,4,1] - 每一排的第一个数和最后一个数都是 1,即 res[i][0] = res[i][i] = 1。那就逐行初始化,第 i 行初始化出 i + 1 个元素,其余的数字另说。
- 其余的数字,等于左上方的数 + 正上方的数。
细节
resize()函数用法
改变容器的大小,使得其包含n个元素。常见三种用法。
-
如果n小于当前的容器大小,那么则保留容器的前n个元素,去除超过的部分。
-
如果n大于当前的容器大小,则通过在容器结尾插入适合数量的元素使得整个容器大小达到n。且如果给出val,插入的新元素全为val,否则,执行默认构造函数。
-
如果n大于当前容器的容量时,则会自动重新分配一个存储空间。
v.resize(n,val);
-
n:这是新的向量(vector)大小。
-
val:如果n大于当前向量(vector)大小,则将value(val)插入添加的空间中。
-
例如:res[1,2,3,4,5,6,7,8,9,10]
res.resizie(5) 后变为 [1,2,3,4,5]
res.resize(7,0) 后变为[1,2,3,4,5,0,0]
代码
class Solution {
public:
vector<vector<int>> generate(int numRows) {
// 初始化有 numRows 行,多少列未知
vector<vector<int>> res(numRows);
// 具体每行的数据填写
for(int i = 0; i < numRows; i++){
// 给每一行确定个数,第 i 行初始化为 i + 1 个 空
res[i].resize(i + 1);
//开头和末尾是1
res[i][0] = res[i][i] = 1;
for(int j = 1; j < i; j++){ // 中间的数据为第 1 列 ~ 第 i - 1 列
res[i][j] = res[i - 1][j - 1] + res[i - 1][j]; // 左上方的数 + 正上方的数
}
}
return res;
}
};
三、杨辉三角 II
题目
给定一个非负索引 rowIndex,返回「杨辉三角」的第 rowIndex 行。
在「杨辉三角」中,每个数是它左上方和右上方的数的和。
思路
同上
细节
res[i].resize(i + 1);
代码
class Solution {
public:
vector<int> getRow(int rowIndex) {
vector<vector<int>> res(rowIndex + 1); // 数组大小应为 rowIndex + 1 (0 ~ rowIndex)
for(int i = 0; i < rowIndex + 1; i++){
res[i].resize(i + 1);
res[i][0] = res[i][i] = 1;
for(int j = 1; j < i; j++){
res[i][j] = res[i - 1][j - 1] + res[i - 1][j];
}
}
return res[rowIndex];
}
};
四、区域和检索 - 数组不可变
题目
给你一个四位 正 整数 num 。请你使用 num 中的 数位 ,将 num 拆成两个新的整数 new1 和 new2 。new1 和 new2 中可以有 前导 0 ,且 num 中 所有 数位都必须使用。
- 比方说,给你 num = 2932 ,你拥有的数位包括:两个 2 ,一个 9 和一个 3 。一些可能的 [new1, new2] 数对为 [22, 93],[23, 92],[223, 9] 和 [2, 329] 。
请你返回可以得到的 new1 和 new2 的 最小 和。
思路
- 先利用循环结构得到每一位数并将其存在 digit 数组中
- 排序之后,两小位放在十位位置可以使数最小,两个数相加也是最小。
细节
代码
class Solution {
public:
int minimumSum(int num) {
vector<int> digit;
while(num){
digit.push_back(num % 10);
num /= 10;
}
sort(digit.begin(), digit.end());
return((digit[0] + digit[1]) * 10 + digit[2] + digit[3]);
}
};
五、统计能整除数字的位数
题目
给你一个整数 num ,返回 num 中能整除 num 的数位的数目。
如果满足 nums % val == 0 ,则认为整数 val 可以整除 nums 。
细节
用 temp 去迭代,num 只用在判断时出场一次就可以了。
代码
class Solution {
public:
int countDigits(int num) {
int cnt = 0;
int temp = num;
while(temp){
int digit = temp % 10;
temp /= 10;
if(num % digit == 0) cnt++;
}
return cnt;
}
};
六、比赛中的配对次数
题目
给你一个整数 n ,表示比赛中的队伍数。比赛遵循一种独特的赛制:
- 如果当前队伍数是 偶数 ,那么每支队伍都会与另一支队伍配对。总共进行 n / 2 场比赛,且产生 n / 2 支队伍进入下一轮。
- 如果当前队伍数为 奇数 ,那么将会随机轮空并晋级一支队伍,其余的队伍配对。总共进行 (n - 1) / 2 场比赛,且产生 (n - 1) / 2 + 1 支队伍进入下一轮。
返回在比赛中进行的配对次数,直到决出获胜队伍为止。
思路
对照着题干写。
代码
class Solution {
public:
int numberOfMatches(int n) {
int temp = n;
int res = 0;
while(temp != 1){
if(temp % 2 == 0){
res = res + temp / 2;
temp = temp / 2;
} else {
res = res + (temp - 1) / 2;
temp = (temp - 1) / 2 + 1;
}
}
return res;
}
};
七、公因子的数目
题目
给你两个正整数 a 和 b ,返回 a 和 b 的 公因子的数目。
如果 x 可以同时整除 a 和 b ,则认为 x 是 a 和 b 的一个 公因子 。
思路
当且仅当两个数均能整除这个因子时,这个因子是公因子。
代码
class Solution {
public:
int commonFactors(int a, int b) {
int cnt = 0;
for(int x = 1; x <= a && x <= b; x++){
if(a % x == 0 && b % x == 0){
cnt++;
}
}
return cnt;
}
};
八、自除数
题目
自除数 是指可以被它包含的每一位数整除的数。
- 例如,128 是一个 自除数 ,因为 128 % 1 == 0,128 % 2 == 0,128 % 8 == 0。
自除数 不允许包含 0 。
给定两个整数 left 和 right ,返回一个列表,列表的元素是范围 [left, right](包括两个端点)内所有的 自除数 。
思路
- 直接模拟 [left,right] 每一个数 x,对于每一个数,进行判断是否有效
- 判断每一位上的数 digit, 使得 x % digit == 0
digit == 0时,或者 x 不能整除 digit 时,则无效
细节
digit == 0 || x % digit != 0
等价于
!digit || x % digit
代码
class Solution {
public:
vector<int> selfDividingNumbers(int left, int right) {
vector<int> res;
for(int x = left; x <= right; x++){
int temp = x;
bool flag = true;
while(temp){
int digit = temp % 10;
temp /= 10;
if(digit == 0 || x % digit != 0) flag = false;
}
if(flag) res.emplace_back(x);
}
return res;
}
};
总结
- 双指针法
- v.resize(n,val)用法
- resize( )函数用法
- 如何得到一个整数的每一位数字
- 用位运算化简表达式
digit == 0 || x % digit != 0
等价于!digit || x % digit