2020-8-2
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;
}
};
- 双端队列+模拟
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. 排布二进制网格的最少交换次数
第一反应其实是宽搜,但随即发现是
的时间复杂度。
然后想到其实类似于冒泡排序求交换次数的一道题目,于是就套用了求逆序对的那道题目的代码。
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;
}
};
- 贪心+模拟冒泡
时间复杂度:
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;
}
};
- 双指针
以相同的数字作为数组的分割点,分段统计最大值,比如:
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;
}
};