Leetcode 第273场周赛题解

第一次打leetcode的比赛,打的virtual,简单说下每题的思路。
反转两次的数字
大意:判断一个数字翻转两次后是否还是原来的数字,翻转后要去掉前导零。

只要末位不是零翻转两次肯定没变化,要特判一下0
代码:

class Solution {
public:
    bool isSameAfterReversals(int num) {
        if(num == 0) return true;
        return num % 10;
    }
};

执行所有后缀指令
大意:给一个长度为n的URDL操作序列和一个起点,问从0~n-1开始按照操作序列顺序移动,在不越界的情况下能移动多少次。

没想到简单的办法,暴力模拟一下也不超时,复杂度O(n2)。
代码:

class Solution {
public:
    vector<int> executeInstructions(int n, vector<int>& startPos, string s) {
        vector<int> ans;
        for(int i = 0;i < s.size();++i){
            int r = startPos[0];
            int c = startPos[1];
            for(int j = i; j < s.size();++j){
                if(s[j] == 'L'){
                    c -= 1;
                }else if(s[j] == 'R'){
                    c += 1;
                }else if(s[j] == 'U'){
                    r -= 1;
                }else{
                    r += 1;
                }
                if(r >= n || c >= n || r < 0 || c < 0){
                    ans.push_back(j-i);
                    break;
                }
                if(j == s.size()-1){
                    ans.push_back(j-i+1);
                }
            }
        }
        return ans;
    }
};

相同元素的间隔之和
大意:给一个数组,问每个数字与相同数字下标的距离和。

没太多时间思考,写了个空间复杂度很爆炸的方法。把每个元素分两类统计,一个是在该元素前面的,一个是在该元素后面的,比如该元素下标是i,sum[i]表示该元素下标集合的前缀和,j表示该元素是相同元素中的第几个。m表示该类元素的个数,那么第一类就是 j×i - sum[j-1],第二类就是(sum[m-1] - sum[j]) - 1LL×(m-j-1)×i。具体实现看代码。时间复杂度O(N),空间复杂度O(N),但常数极度爆炸。pos数组改成哈希表可能会好一点。
代码:

class Solution {
public:
    vector<long long> getDistances(vector<int>& a) {
        int n = a.size();
        vector<long long> ans = vector<long long>(n,0);
        vector<vector<int>> pos = vector<vector<int>>(1e5+1,vector<int>());
        vector<long long> sum = vector<long long>(1e5+1,0);
        for(int i = 0 ; i < n; ++ i)
            pos[a[i]].push_back(i);
        for(int i = 0 ;i < 1e5+1;++i){
            int m = pos[i].size();
            sum[0] = m?pos[i][0]:0;
            for(int j = 1;j < m; j++) sum[j] = 1LL*pos[i][j]+sum[j-1];
            for(int j = m-1;j >= 0;-- j){
                long long pre = 0,aft = 0;
                if(j > 0) pre = 1LL*j*pos[i][j] - sum[j-1];
                if(j < m-1) aft = (sum[m-1] - sum[j]) - 1LL*(m-j-1) * pos[i][j];
                ans[pos[i][j]] = pre + aft;
            }
        }
        
        return ans;
    }
};

还原原数组
大意:原来有一个数组a和一个k,生成两个数组:b[i] = a[i] + k,c[i] = c[i] - k。现在只有混起来的b,c数组d。求a和k。

继续暴力,考虑一下b和c的关系,显然b[i] = c[i] + 2×k,那么就先对数组排个序,假设k确定了,那么只需要从0开始,为每个数找到d[i] + 2*k,如果找不到或者已经被前面的数用完了,那么这个k就是非法的。这个k其实也很好枚举,排序后的d[0],其他n-1个数和他只有n-1种组合,k也只有n-1个,时间复杂度O(n2)。
代码:

class Solution {
public:
    vector<int> recoverArray(vector<int>& nums) {
        int n = nums.size();
        sort(nums.begin(),nums.end());
        unordered_map<int,int> mp;
        vector<int> ans;
        int kk = 0;
        for(int i = 0 ; i< n; ++ i) mp[nums[i]]++;
        for(int i = 1; i <= n/2; ++ i){
            int k = (nums[i] - nums[0])/2;
            if(!k || (nums[i]-nums[0])%2) continue;
            bool flag = 1;
            mp[nums[i]]--;
            mp[nums[0]]--;
            vector<int> temp;
            for(int j = 0;j < n; ++ j){
                if(!mp[nums[j]]) continue;
                int next = nums[j] + 2*k;
                if(!mp[next]){
                    flag = false;
                    break;
                }
                mp[next]--;
                mp[nums[j]]--;
                temp.push_back(next);
                temp.push_back(nums[j]);
            }
            for(auto x:temp) mp[x]++;
            mp[nums[i]]++;
            mp[nums[0]]++;
            if(flag){
                kk = k;
                break;
            }
        }
        for(int i = 0;i < n; ++ i){
            if(mp[nums[i]] && mp[nums[i]+2*kk]){
                ans.push_back(nums[i]+kk);
                mp[nums[i]]--;
                mp[nums[i]+2*kk]--;
            }
        }
        
        return ans;
    }
};
上一篇:7-5 悄悄关注 (25 分)


下一篇:蓝桥杯 算法训练 P0804