LeetCode题库学习笔记(2022.10.18-2022.10.27)

LeetCode每日一题 共十题

  • 902. 最大为 N 的数字组合(2022.10.18)
    • 题目详情
    • 解题思路
    • 代码部分
  • 1700. 无法吃午餐的学生数量(2022.10.19)
    • 题目详情
    • 解题思路
    • 代码部分
  • 779. 第K个语法符号(2022.10.20)
    • 题目详情
    • 解题思路
    • 代码部分
    • 代码总结反思
  • 901. 股票价格跨度(2022.10.21)
    • 题目详情
    • 解题思路
    • 代码部分
      • 方法1:暴力解法
      • 方法2:单调栈方法
  • 1235. 规划兼职工作(2022.10.22)
    • 题目详情
    • 解题思路
    • 代码部分
    • 代码总结反思
  • 1768. 交替合并字符串(2022.10.23)
    • 题目详情
    • 解题思路
    • 代码部分
      • 方法1:
      • 方法2:
  • 915. 分割数组(2022.10.24)
    • 题目详情
    • 解题思路
    • 代码部分
  • 934. 最短的桥(2022.10.25)
    • 题目详情
    • 解题思路
    • 代码部分
  • 862. 和至少为 K 的最短子数组(2022.10.26)
    • 题目详情
    • 解题思路
    • 代码部分
    • 总结反思(~~发现了一点自身编程思维上的错误~~ )
  • 1822. 数组元素积的符号(2022.10.27)
    • 题目详情
    • 解题思路
    • 代码部分

902. 最大为 N 的数字组合(2022.10.18)

题目详情

LeetCode题目:902. 最大为 N 的数字组合

解题思路

n的长度为n_Lengthdigits的长度为digits_Length,从digits取值所组+成的结果值digits_num的位数记为k(k取1,2,3,……,n_Length)。

k时,其满足条件的结果为digits_Length的k次方,将每个结果相加存到ans中得到其中一部分结果;

K==n_Length时,则从digits_num的最高位开始依次考虑,记当前位为第k位(第1位表示个位):

1.如果digits_num的第k位(最高位为k位)的值小于n的第k位的值,那么表示digits_num中其余位可以从digits中任取,则共计digits_Length的k-1次方的结果符合条件,将其算入ans中。

2.如果digits_num的第k位的值等于n的第k位的值,那么就考虑digits_num的后一位n的后一位的大小关系,即k的值减少1,直到考虑到digits_nums的最低位。(注意:当digits_num的最低位和n的最低位相等时,说明此时组成的digits_num刚好等于n,也需要加入总结果的ans中。边界值问题

3.如果digits_num的第k位的值大于n的第k位的值,那么不论后面位取什么都不会满足条件。

代码部分

class Solution {
   
public:
    int atMostNGivenDigitSet(vector<string>& digits, int n) {
   

        int digits_Length = digits.size();
        int n_Length = 0;           //得到n的位数
        int ans = 0;
        int n_digit[10];            //存n的每一位数字       
        while(n/10 != 0){
              //将n的每一位存到n_digit中
            n_digit[n_Length++]=n%10;
            n/=10;
        }
        if(n!=0)    n_digit[n_Length++]=n;

		//当组成的位数小于n的位数时,其结果如下
        for(int i = n_Length-1;i>0;i--){
   
            ans += pow(digits_Length,i);  
        }
        
        //当组成的位数等于n的位数时,需要分三种情况进行处理
        int j = n_Length-1;
        for(int i = 0;i<digits_Length;i++){
   
        	//边界值
            if(j == -1 ){
   
                ans++;
                break;
            }
            //如果取的数小于n的当前位数
            //atoi(digits[i].c_str())是将digit[i]从string类型转为整型
            if(atoi(digits[i].c_str())<n_digit[j]){
   
                ans += pow(digits_Length,j);
            }
            //如果取的数等于当前位数
            else if(atoi(digits[i].c_str())==n_digit[j]){
   
                j--;
                i = -1;
            }
            else    break;       
        }
        return ans;
    }
};

1700. 无法吃午餐的学生数量(2022.10.19)

题目详情

LeetCode题目:1700.无法吃午餐的学生数量

解题思路

使用ij分别作为studentssandwiches的指针。按照题目所给的思路:

  • 如果队列最前面的学生 喜欢 栈顶的三明治,那么会 拿走它 并离开队列。
  • 否则,这名学生会 放弃这个三明治 并回到队列的尾部。
  • 这个过程会一直持续到队列里所有学生都不喜欢栈顶的三明治为止。

那么需要解决的问题有以下三个:

  1. 如何表示学生 放弃这个三明治 并回到队列的尾部?
  2. 当学生喜欢三明治时(students[j] == sandwiches[i]),使用何种方法表示出栈?
  3. 怎么去判断队列里的所有学生都不喜欢栈顶的三明治?

我的解题方法是:

  • 通过移动指针 j 来实现队列循环,当移动前的指针 j 指到 students 的末尾时,将指针 j 指向 students 的起始位置即可。
  • 出栈可以将指针 i 后移一位。
  • 使用 Vectorerase() 函数删除当前匹配到的学生students[j],此时指针 j 的变换情况有两种:如果删除的位置不是students的末尾的话,则不需要移动指针 j;反之则需要将指针 j 指向初始位置。
  • 使用一个bool类型的变量 change 来判断队列里的所有学生都不喜欢栈顶的三明治。当一次队列循环(从students的起始位置到结束位置为一个循环)内有学生喜欢三明治时,将 change 置为true;当一次队列循环结束后,判断 change 是否为true,如果为true则将其置为false并继续下一轮队列循环,否则结束队列循环过程。

代码部分

class Solution {
   
public:
    int countStudents(vector<int>& students, vector<int>& sandwiches) {
   
        int j = 0;                      //student的指针
        int i = 0;                      //sandwiches的指针
        bool change = false;            //用于判断一轮循环后是否有学生拿了三明治   
        int ans = students.size();      //初始结果位学生的总人数,用于返回最终结果
        while(i != sandwiches.size()){
   
            //当三明治栈顶被拿走时, 学生长度减少一个,输出结果减少一个,栈顶退出:i++
            if(students[j] == sandwiches[i]){
   
                //出栈只需让i++
                i++;       

                //匹配到就直接删除该元素,j就会自动指向下一个
                students.erase(students.begin() + j);   

                //如果j当前指向的是末尾元素,要将j归于0号位置
                if(j==students.size()) j=0;

                //匹配到后无法吃到午餐的学生数量要减少一个
                ans--;          
                change = true;
            }
            //不匹配时只要改变student的指针j,并判断是否在student循环了一圈后仍然未有sandwiches出栈
            else{
   
                if(j<students.size()-1){
   
                    j++;
                }
                else{
   
                    if(change){
   
                        change = false;
                        j = 0;
                    }
                    else break;
                }
            }
        }
        return ans;
    }
};

779. 第K个语法符号(2022.10.20)

题目详情

LeetCode题目:799.第k个语法符号

解题思路

找规律:

第一行:0
第二行:01
第三行:01,10                                             (第一个对称轴【第2个数与第3个数之间】是镜像) 
第四行:01,10,10,01                                       (第二个对称轴【第4个数与第5个数之间】是异或)
第五行:01,10,10,01,10,01,01,10                           (第三个对称轴【第8个数与第9个数之间】是镜像)
第六行:01,10,10,01,10,01,01,10,10,01,01,10,01,10,10,01

可以发现在前六行中满足:
从当前行到下一行,数量翻倍,下一行的前半部分等于上一行,下一行变换(除了第一行到第二行以外)只有两种情况:

    i.从偶数行到奇数行时,后半部分与前半部分关于中间位置是单个数分别对称
    ii.从奇数行到偶数行时,后半部分与前半部分关于中间位置是以两个数为一组分别对称

因此猜测在之后所有行都满足这个关系,该结论可以通过数学归纳法予以证明。

对于其中的 情况ii 还可以进一步转化为,对于单个数而言,是关于中心位置对称的异或关系(即如果后半部分的一个数为1,那么与其关于中心位置对称的数就是0)

根据以上所述,对于第n行的第k个字符的值的求法,显然不论n为多少,都不影响最终的结果,只有k变量才会影响最终结果。

那么我们只需不断通过对称关系(数值上要么相同要么异或)将 第一位或者第二位对应的数原本k所指的数 联系起来,不断减少k的值,直到k<=2时,就能确定原本的k所指的数与第一个数或者第二个数的关系。

代码部分

class Solution {
   
public:
    int kthGrammar(int n, int k) {
   
        if(k==1)    return 0;
        if(k==2)    return 1;
        int ans;            //存放结果
        int m ;             //m=1表示是第三行的对称轴,
        //进一步转化为m为单数,对称关系就为镜像,m为偶数,对称关系为奇数,通过对称不断缩小k的大小,直至k=1或者k=2
        bool turn_over = false;

你可能感兴趣的:(leetcode,学习,算法,c++)