leetcodeday12 768,769,775,782,792,795

224 阅读4分钟

795. Number of Subarrays with Bounded Maximum

链接:leetcode.com/problems/nu…

题意:给一串数,求最大值在[L, R]的子段数

思路:首先用>R的数讲整个序列分为若干段,每一小段从左向右扫描直到最后一个在[L, R]的数,每个位置i为左端点共有(r - lowerbound + 1)个区间符合条件,lowerbound是A[i]右边第一个在[L, R]中的数的位置

代码:

class Solution {
public:
    int work(int l, int r, vector<int>& A, int L, int R)
    {
        vector<int> a;
        for(int i = l; i <= r; i++)
            if(A[i] >= L && A[i] <= R)
                a.push_back(i);
        if(a.size() == 0)
            return 0;
        int lowerbound = 0;
        int s = 0;
        for(int i = l; i <= r; i++)
        {
            if(i > a[lowerbound])
                lowerbound++;
            if(lowerbound >= a.size())
                break;
            s += r - a[lowerbound] + 1;
        }
        return s;
    }
    int numSubarrayBoundedMax(vector<int>& A, int L, int R) {
        int n = A.size();
        int pre = -1;
        int ans = 0;
        for(int i = 0; i < n; i++)
            if(A[i] > R)
            {
                ans += work(pre + 1, i - 1, A, L, R);
                pre = i;
            }
        ans += work(pre + 1, n - 1, A, L, R);
        return ans;
    }
};

792. Number of Matching Subsequences

链接:leetcode.com/problems/nu…

题意:给出一个字符串序列L和一个字符串S,问L中有多少个是S的子序列,所有字符都是小写字母

思路:用数组a[i][j]表示位置i处后一个字母j在什么位置,然后一个个比较

代码:

class Solution {
public:
    int anext[50005][35];
    int afirst[35];
    int next[35];
    int numMatchingSubseq(string S, vector<string>& words) {
        int n = words.size();
        int ans = 0;
        for(int i = 0; i < 26; i++)
            next[i] = 1e9;
        for(int i = S.length() - 1; i >= 0; i--)
        {
            for(int j = 0; j < 26; j++)
                anext[i][j] = next[j];
            next[S[i] - 'a'] = i;
        }
        for(int i = 0; i < 26; i++)
            afirst[i] = next[i];
        for(int i = 0; i < n; i++)
        {
            int leni = words[i].length();
            int k = 0;
            int j = afirst[words[i][0] - 'a'];
            if(j == 1e9)
                continue;
            while(true)
            {
                k++;
                if(k >= leni)
                    break;
                j = anext[j][words[i][k] - 'a'];
                if(j >= S.length())
                    break;
            }
            if(k >= leni)
                ans++;
        }
        return ans;
    }
};

782. Transform to Chessboard

链接:leetcode.com/problems/tr…

题意:给一个01组成的N*N矩阵,每次可以交换2行或2列,问最少多少次可以得到一个国际象棋棋盘

思路:首先注意到有解的充要条件是(1)每行,每列的0、1个数都和最终目标相同(2)任取一个矩形,它的四个角总是2黑2白或4黑或4白

当有解时,在移动行列时只需关心第一行和第一列即可,而行列的交换方法是类似的

以行为例,如果n是奇数,统计未归位的格子数x,如果x是偶数则行需要交换x/2次,如果x是奇数则行需要交换(n - x) / 2次;如果n是偶数,仍然统计未归位的格子数x,需要交换min(x, n - x)/2次

代码:

class Solution {
public:
    int movesToChessboard(vector<vector<int>>& board) {
        int n = board.size();
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                if(board[0][0] ^ board[i][0] ^ board[0][j] ^ board[i][j])
                    return -1;
        int srow = 0, scol = 0, swapRow = 0, swapCol = 0;
        for(int i = 0; i < n; i++)
        {
            srow += board[i][0];
            scol += board[0][i];
            swapRow += board[i][0] == (i & 1);
            swapCol += board[0][i] == (i & 1);
        }
        if(srow < n / 2 || srow > (n + 1) / 2 || scol < n / 2 || scol > (n + 1) / 2)
            return -1;
        if(n & 1)
        {
            if(swapRow & 1)
                swapRow = n - swapRow;
            if(swapCol & 1)
                swapCol = n - swapCol;
        }
        else
        {
            swapRow = min(swapRow, n - swapRow);
            swapCol = min(swapCol, n - swapCol);
        }
        return (swapRow + swapCol) / 2;
    }
};

775. Global and Local Inversions

链接:leetcode.com/problems/gl…

题意:给出0 ~ n - 1的一个排列,定义局部逆序对为A[i] > A[i + 1],全局逆序对为A[i] > A[j], i < j,问全局逆序对个数是否大于局部逆序对

思路:也就是求有没有位置相差>1的逆序对,由于给出的是n - 1的排列,对每个A[i], 如果A[i] - i > 1必定存在A[j] < A[i] && j > i + 1,如果i - A[i] > 1必定存在A[i] < A[j] && i > j + 1;不难得出这2个同时也是充分条件

代码:

class Solution {
public:
    bool isIdealPermutation(vector<int>& A) {
        int n = A.size();
        for(int i = 0; i < n; i++)
            if(abs(A[i] - i) >= 2)
                return false;
        return true;
    }
};

768&769 Max Chunks To Make Sorted (II)

链接:leetcode.com/problems/ma…

题意:给出一个序列,将这个序列分块,使得每个块内排好序后,整个序列也有序,求最大分块数

思路:设原序列为A,将A排好序后的序列成为B,从左向右比较A和B,每当A中出现了B中出现过的所有数时块数+1

具体而言,用一个哈希表记录数字出现的次数,在A中出现一次+1,在B中出现一次-1,达到0时将这个数从表中删去;当哈希表为空时块数+1

代码:

class Solution {
public:
    vector<int> brr;
    int maxChunksToSorted(vector<int>& arr) {
        int n = arr.size();
        brr = arr;
        sort(brr.begin(), brr.end());
        int ans = 0;
        unordered_map<int, int> total;
        for(int i = 0; i < n; i++)
        {
            int x = arr[i], y = brr[i];
            if(total.find(x) != total.end())
                total[x]++;
            else
                total[x] = 1;
            if(total[x] == 0)
                total.erase(x);
            if(total.find(y) != total.end())
                total[y]--;
            else
                total[y] = -1;
            if(total[y] == 0)
                total.erase(y);
            if(total.empty())
                ans++;
        }
        return ans;
    }
};