LeetCode 第 200 场周赛

2020-8-2

5475. 统计好三元组

class Solution {
public:
    int countGoodTriplets(vector<int>& ar, int a, int b, int c) {
        int ans = 0, n = ar.size();
        for(int i=0;i<n;i++){
            for(int j=i+1;j<n;j++){
                for(int k=j+1;k<n;k++){
                    if( abs(ar[i]-ar[j])<=a && abs(ar[j]-ar[k])<=b  && abs(ar[i]-ar[k])<=c  ){
                        ans ++;
                    }
                }
            }
        }
        return ans;
    }
};

5476. 找出数组游戏的赢家

  • 双端队列+模拟
class Solution {
public:
    int getWinner(vector<int>& a, int k) {
        deque<int> dq;
        int ans = 0,n = a.size(), i = 0;
        for(int x:a) {
            ans = max(ans,x);
            dq.push_back(x);
        }
        if(k>=n-1) return ans; // k很大,直接返回最大值 *max_element(a.begin(),a.end());
        vector<int> cnt(1000010,0);  // 记录每个数字连赢的次数。
        while(i++<=n){
        	// 取出前两个,把小的放到队尾,大的数赢的次数加1
            int x = dq.front();dq.pop_front();
            int y = dq.front();dq.pop_front();
            if(x<y) swap(x,y);
            dq.push_back(y);
            cnt[y] = 0;
            cnt[x]++;
            if(cnt[x]>= k) return x;
            dq.push_front(x);
        }
        return dq.front(); // 此时队首就是最大的元素,返回即可。
    }
};

其实也可以完全省去真实的模拟步骤,即不需要把元素移动至队尾。

class Solution {
public:
    int getWinner(vector<int>& arr, int k) {
        if(k>=arr.size()-1) return *max_element(arr.begin(),arr.end());
        int cur = arr[0],win = 0;
        for(int i=1;i<arr.size();i++){
            if(cur>arr[i]){
                if(++win>=k) return cur;
            }else{
                cur = arr[i];
                win = 1;
                if(k==1) return cur;
            }
        }
        return *max_element(arr.begin(),arr.end());
    }
};

5477. 排布二进制网格的最少交换次数
第一反应其实是宽搜,但随即发现是 O ( n ! ) O(n!) 的时间复杂度。

然后想到其实类似于冒泡排序求交换次数的一道题目,于是就套用了求逆序对的那道题目的代码。

class Solution {
public:
    int n;
    int minSwaps(vector<vector<int>>& g) {
        n = g.size();
        int cnt = n-1;
        vector<int> vis(n,0), res;
        // 从大到小地 找出 n-1、n-2、…… 1、0
        for(int i=0;i<n;i++){
            int sum = getSum(g,i);
            if(sum<cnt){
                while(sum>=0 && vis[sum]){
                    sum--;
                }
                if(sum>=0) {
                    vis[sum] = 1;
                    res.push_back(sum);
                }
            }else{ 
                while(cnt>=0 && vis[cnt] ){
                    cnt--;
                }
                if(cnt>=0){
                    vis[cnt] = 1;
                    res.push_back(cnt);
                }          
            }
        }
        // 没有满足条件,不可能拼成
        for(int i=0;i<n;i++){
            if(vis[i]==0) return -1;
        }
        reverse(res.begin(),res.end());
        return reversePairs(res);
    }
    
    // 求出每一行从最后开始0的个数
    int getSum(vector<vector<int>>& g,int i){
        int sum = 0 ;
        for(int j=n-1;j>=0;j--){
            if(g[i][j]==0) sum++;
            else break;
        }
        return sum;
    }

    // 利用归并排序求逆序对的个数
    int reversePairs(vector<int>& nums) {
        int n = nums.size();
        vector<int> tmp(n);
        return mergeSort(nums, tmp, 0, n - 1);
    }    
    int mergeSort(vector<int>& nums, vector<int>& tmp, int l, int r) {
        if (l >= r) {
            return 0;
        }
        int mid = (l + r) / 2;
        int inv_count = mergeSort(nums, tmp, l, mid) + mergeSort(nums, tmp, mid + 1, r);
        int i = l, j = mid + 1, pos = l;
        while (i <= mid && j <= r) {
            if (nums[i] <= nums[j]) {
                tmp[pos] = nums[i];
                ++i;
                inv_count += (j - (mid + 1));
            }
            else {
                tmp[pos] = nums[j];
                ++j;
            }
            ++pos;
        }
        for (int k = i; k <= mid; ++k) {
            tmp[pos++] = nums[k];
            inv_count += (j - (mid + 1));
        }
        for (int k = j; k <= r; ++k) {
            tmp[pos++] = nums[k];
        }
        copy(tmp.begin() + l, tmp.begin() + r + 1, nums.begin() + l);
        return inv_count;
    }
};
  • 贪心+模拟冒泡
    时间复杂度: O ( n 2 ) O(n^2)
class Solution {
public:
    int minSwaps(vector<vector<int>>& a) {
        int n = a.size(), ans = 0;
        vector<int> v(n,0);
        for(int i=0;i<n;i++){
            for(int j=n-1;j>=0;j--){
                if(a[i][j]==0){
                    v[i]++;
                }else break;
            }
        }

        for(int i=0;i<n;i++){
            // 如果当前行提供的0的个数小于应该有的0的个数,就往下面找。如果没找到,直接返回-1
            if(v[i]<n-i-1){
                bool flag = false;
                for(int j=i+1;j<n;j++){
                    if( v[j] >= n-i-1 ){
                        ans += j-i;
                        //  模拟冒泡排序的过程,因为只能相邻的交换
                        int temp = v[j];
                        for(int k=j;k>=i+1;k--){
                            v[k] = v[k-1];
                        }
                        v[i] = temp;
                        flag = true;
                        break;
                    }
                }
                if(!flag) return -1;
            }
        }
        return ans;
    }
};
class Solution {
public:
    int maxSum(vector<int>& a1, vector<int>& a2) {
        int M = 1e9+7;
        int m = a1.size(), n = a2.size(), i = 0, j = 0;
        long long t1 = 0, t2 = 0;
        while(i<m || j<n){
            if(i<m && j<n){
                if(a1[i]<a2[j]){
                    t1 += a1[i++];
                }else if(a1[i]>a2[j]){
                    t2 += a2[j++];
                }else{
                    t1 = t2 = max(t1,t2)+a1[i];
                    i++;
                    j++;
                }
            }else if(i<m){
                t1 += a1[i++];
            }else if(j<n){
                t2 += a2[j++];
            }
        }
        return max(t1,t2)%M;
    }
};

5478. 最大得分

  • 双指针

以相同的数字作为数组的分割点,分段统计最大值,比如:

1 3 9 10 12 22 23
2 6 8 9 21 22 25
可以根据相同的数值作为分割点,分割成:
[1 3]    + 9 + [10 12] + 22 + [23] 
[2 6 8]  + 9 + [21]    + 22 + [25]
max(4,16)+ 9 + max(22,21) + 22 + max(23,25)
16 + 9 + 22 + 25 = 72

那现在的问题实际上就是如何快速求出所有的分割点,并且同时求出分段和。

t1,t2分别记录两个数组在遇到角标i,j的时候能够产生的最大值。

class Solution {
public:
    int maxSum(vector<int>& a1, vector<int>& a2) {
        int M = 1e9+7;
        int m = a1.size(), n = a2.size(), i = 0, j = 0;
        long long t1 = 0, t2 = 0;
        while(i<m || j<n){
            if(i<m && j<n){
                if(a1[i]<a2[j]){
                    t1 += a1[i++];
                }else if(a1[i]>a2[j]){
                    t2 += a2[j++];
                }else{
                    t1 = t2 = max(t1,t2)+a1[i];
                    i++;
                    j++;
                }
            }else if(i<m){
                t1 += a1[i++];
            }else if(j<n){
                t2 += a2[j++];
            }
        }
        return max(t1,t2)%M;
    }
};

猜你喜欢

转载自blog.csdn.net/qq_44846324/article/details/107746810
今日推荐