Bootstrap

6.30 数学中等&数组简单 400 357 2011 1929 1720 2574

400 第N位数字

给你一个整数 n ,请你在无限的整数序列 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, …] 中找出并返回第 n 位上的数字。

思路:首先是需要定位是在哪一个整数中的第几位数字。

令这个整数为ans,第N位数字为整数ans的第i位的数字。
为了提高搜查效率,按照ans的位数分为不同区间,ans为x位数,则ans之前会有: 1 ∗ 1 0 0 ∗ 9 + 2 ∗ 1 0 1 ∗ 9... x ∗ 1 0 x − 1 ∗ 9 1*10^0*9+2*10^1*9...x*10^{x-1}*9 11009+21019...x10x19个数字(这里为了方便理解x设定为>2,但其实是x>1),也就是当ans不为1位数的时候,我们是可以根据这个规律大致获知ans的x位数,从而获取i和ans的具体值。

class Solution {
public:
    int findNthDigit(int n) {
        if(n / 10 == 0){return n;}//个位数直接返回
        int m = 0 , i = 0 , x = 1 , ans = 0;
        long long end = 0 , begin = 0;
        end = n - 9*pow(10,x-1)*x;
        while( end > 0 ){
            x++;
            end -= 9*pow(10,x-1)*x;//最后一次为负数
        }
        end += 9*pow(10,x-1)*x;//还原end,确定N最大可以包含(x-1)位数的完整区间,则能确定N位于x位数,end为第x位数区间的第end个数字
        i = end % x;//位于ans的第1,2,...,0位数字 
        m = end / x;//ans之前有m个数字
        i == 0 ? m--:m;//如果i=0,我这里表示的是某一整数的最后一位,需要降1,可以用N=10、11、12去验证一下【是对m做了处理,没有对i做处理,怎么方便怎么来吧】
        for(int j = 1 ; j < x ; j++){
            begin += pow(10,j-1)*9;
        }
        ans = begin + m + 1;
        //x位数区间的第m个数的第i位数字即为ans
        while( i > 0 && i < x){
            ans /= 10;
            i++;
        }
        return ans % 10;//获取第i位数
    }
};

这道题还可以使用二分查找,但还没复习就先占个位在这里,官方题解有给答案。

357 统计各位数字都不同的数字个数

给你一个整数 n ,统计并返回各位数字都不同的数字 x 的个数,其中 0 < = x < 1 0 n 0 <= x < 10^n 0<=x<10n

思路:概率论

位数为 1:
有 10 种可能的数字(0 到 9)。
位数为 2:
第一位有 9 种选择(1 到 9),因为第一位不能是0。
第二位有 9 种选择(0 到 9,但不包括第一位的数字)。
总共有9×9=81 种可能。
位数为 3:
第一位有 9 种选择(1 到 9)。
第二位有 9 种选择(0 到 9,但不包括第一位的数字)。
第三位有 8 种选择(不包括前两位的数字)。
总共有 9×9×8=648 种可能。
。。。
n=3的话,需要把位数为1 2 3的可能性全部加起来

class Solution {
public:
    int countNumbersWithUniqueDigits(int n) {
        if( n == 0){return 1;}
        int count = 1; // 包含0的情况
        int current = 9; // 第一位的选择有9种(1-9)
        int availableDigits = 9; // 可用的数字总数(0-9)
        
        for(int i = 0 ; i < n ;i++){
            count += current;
            if(availableDigits > 0){
                current *= availableDigits;
                availableDigits--;
            }
        }
        return count;
    }
};

2011 执行操作后的变量值

存在一种仅支持 4 种操作和 1 个变量 X 的编程语言:
++X 和 X++ 使变量 X 的值 加 1
–X 和 X-- 使变量 X 的值 减 1
最初,X 的值是 0
给你一个字符串数组 operations ,这是由操作组成的一个列表,返回执行所有操作后, X 的 最终值 。

class Solution {
public:
    int finalValueAfterOperations(vector<string>& operations) {
        int x = 0;
        for(string o : operations){
            if(o[0] == '-'){--x;}
            else if(o[2] == '-'){x--;}
            else if(o[0] == '+'){++x;}
            else if(o[2] == '+'){x++;}
        }
        return x;
    }
};

优化:“X++” “++X”均为x++,其实大差不差,但理解上确实上面的有欠缺,这里无所谓加法/减法前置后置的

class Solution {
public:
    int finalValueAfterOperations(vector<string>& operations) {
        int x = 0;
        for (auto &op : operations) {
            if (op == "X++" || op == "++X") {
                x++;
            } else {
                x--;
            }
        }
        return x;
    }
};

1929 数组串联

给你一个长度为 n 的整数数组 nums 。请你构建一个长度为 2n 的答案数组 ans ,数组下标 从 0 开始计数 ,对于所有 0 <= i < n 的 i ,满足下述所有要求:
ans[i] == nums[i]
ans[i + n] == nums[i]
具体而言,ans 由两个 nums 数组 串联 形成。

返回数组 ans 。

class Solution {
public:
    vector<int> getConcatenation(vector<int>& nums) {
        vector<int> ans;
        int len = nums.size();
        for(int i = 0 ; i < 2*len ; i++){
            int s = i;
            if( s >= len ){ s -= len;}
            ans.push_back(nums[s]);
        } 
        return ans;
    }
};

优化:完全没必要新建立ans数组,直接在nums上做修改就可以

class Solution {
public:
    vector<int> getConcatenation(vector<int>& nums) {
        int len = nums.size();
        for(int i = 0 ; i < len ; i++){
            nums.push_back(nums[i]);
        } 
        return nums;
    }
};

1720 解码异或后的数组

未知 整数数组 arr 由 n 个非负整数组成。
经编码后变为长度为 n - 1 的另一个整数数组 encoded ,其中 encoded[i] = arr[i] XOR arr[i + 1] 。例如,arr = [1,0,2,1] 经编码后得到 encoded = [1,2,3] 。
给你编码后的数组 encoded 和原数组 arr 的第一个元素 first(arr[0])。
请解码返回原数组 arr 。可以证明答案存在并且是唯一的。

思路:a ^ b = c 已知a c 则b = a ^ c
class Solution {
public:
    vector<int> decode(vector<int>& encoded, int first) {
        vector<int> ans;
        int a = first;
        ans.push_back(first);
        for(int i = 0 ; i < encoded.size() ; i++){
            int c = encoded[i];
            ans.push_back(a ^ c);
            a = a^c;
        }
        return ans;
        

    }
};

2574 左右元素和的差值

给你一个下标从 0 开始的整数数组 nums ,请你找出一个下标从 0 开始的整数数组 answer ,其中:
answer.length == nums.length
answer[i] = |leftSum[i] - rightSum[i]|
其中:
leftSum[i] 是数组 nums 中下标 i 左侧元素之和。如果不存在对应的元素,leftSum[i] = 0 。
rightSum[i] 是数组 nums 中下标 i 右侧元素之和。如果不存在对应的元素,rightSum[i] = 0 。
返回数组 answer 。

class Solution {
public:
    vector<int> leftRightDifference(vector<int>& nums) {
        //暴力解题
        vector<int> ans;
        for(int i = 0 ; i < nums.size() ; i++){
            int left = 0 , right = 0;
            for(int j = 0 ; j < i ; j++){
                left += nums[j];
            }
            for(int t = i+1 ; t <nums.size() ; t++ ){
                right += nums[t];
            }
            ans.push_back(abs(left-right));
        }
        return ans;
        
    }
};
;