LeetCode题目:902. 最大为 N 的数字组合
设n的长度为n_Length,digits的长度为digits_Length,从digits取值所组+成的结果值digits_num的位数记为k(k取1,2,3,……,n_Length)。
当k
当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;
}
};
LeetCode题目:1700.无法吃午餐的学生数量
使用i,j分别作为students和sandwiches的指针。按照题目所给的思路:
那么需要解决的问题有以下三个:
我的解题方法是:
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;
}
};
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;