795. Number of Subarrays with Bounded Maximum
题意:给一串数,求最大值在[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
题意:给出一个字符串序列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
题意:给一个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
题意:给出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)
题意:给出一个序列,将这个序列分块,使得每个块内排好序后,整个序列也有序,求最大分块数
思路:设原序列为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;
}
};