力扣刷题 | 01 LeetCode283 移动零、118 杨辉三角、303 区域和检索 - 数组不可变、2520 统计能整除数字的位数、1688 比赛中的配对次数、2427 公因子的数目、自除数

慢慢来,比较快。
尽量保证学过的都能复现,没弄懂的就多学几遍多敲几遍,总能成功的。


一、移动零

题目

给定一个数组 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]
    [1,2,1]
    [1,3,3,1]
    [1,4,6,4,1]
  2. 每一排的第一个数和最后一个数都是 1,即 res[i][0] = res[i][i] = 1。那就逐行初始化, i 行初始化出 i + 1 个元素,其余的数字另说。
  3. 其余的数字,等于左上方的数 + 正上方的数。

细节

resize()函数用法

改变容器的大小,使得其包含n个元素。常见三种用法。

  1. 如果n小于当前的容器大小,那么则保留容器的前n个元素,去除超过的部分。

  2. 如果n大于当前的容器大小,则通过在容器结尾插入适合数量的元素使得整个容器大小达到n。且如果给出val,插入的新元素全为val,否则,执行默认构造函数。

  3. 如果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 的 最小 和。

在这里插入图片描述

思路

  1. 先利用循环结构得到每一位数并将其存在 digit 数组中
  2. 排序之后,两小位放在十位位置可以使数最小,两个数相加也是最小。

细节

在这里插入图片描述

代码

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](包括两个端点)内所有的 自除数 。
在这里插入图片描述

思路

  1. 直接模拟 [left,right] 每一个数 x,对于每一个数,进行判断是否有效
  2. 判断每一位上的数 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;
    }
};

总结

  1. 双指针法
  2. v.resize(n,val)用法
  3. resize( )函数用法
  4. 如何得到一个整数的每一位数字
  5. 用位运算化简表达式 digit == 0 || x % digit != 0等价于!digit || x % digit
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值